diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
commit | 3f619478f796eddbba6e39502fe941b285dd97b1 (patch) | |
tree | e2c7b5777f728320e5b5542b6213fd3591ba51e2 /tests/mysql_client_test.c | |
parent | Initial commit. (diff) | |
download | mariadb-3f619478f796eddbba6e39502fe941b285dd97b1.tar.xz mariadb-3f619478f796eddbba6e39502fe941b285dd97b1.zip |
Adding upstream version 1:10.11.6.upstream/1%10.11.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/mysql_client_test.c')
-rw-r--r-- | tests/mysql_client_test.c | 22495 |
1 files changed, 22495 insertions, 0 deletions
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c new file mode 100644 index 00000000..c0077681 --- /dev/null +++ b/tests/mysql_client_test.c @@ -0,0 +1,22495 @@ +/* Copyright (c) 2002, 2014, Oracle and/or its affiliates. + Copyright (c) 2008, 2022, MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +/*************************************************************************** + This is a test sample to test the new features in MySQL client-server + protocol + + Main author: venu ( venu@mysql.com ) +***************************************************************************/ + +/* + XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST + DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. +*/ + + +/* + The fw.c file includes all the mysql_client_test framework; this file + contains only the actual tests, plus the list of test functions to call. +*/ +#ifdef _MSC_VER +#pragma warning (disable : 4267) +#endif + +#include "mysql_client_fw.c" +#ifndef _WIN32 +#include <arpa/inet.h> +#endif + +#include "my_valgrind.h" + +static const my_bool my_true= 1; + + +/* Query processing */ + +static my_bool get_reconnect(MYSQL *mysql) +{ +#ifdef EMBEDDED_LIBRARY + return mysql->reconnect; +#else + my_bool reconnect; + mysql_get_option(mysql, MYSQL_OPT_RECONNECT, &reconnect); + return reconnect; +#endif +} + +static void client_query() +{ + int rc; + + myheader("client_query"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1(" + "id int primary key auto_increment, " + "name varchar(20))"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1(id int, name varchar(20))"); + myquery_r(rc); + + rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('mysql')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('monty')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('venu')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')"); + myquery(rc); + + rc= mysql_query(mysql, "UPDATE t1 SET name= 'updated' " + "WHERE name= 'deleted'"); + myquery(rc); + + rc= mysql_query(mysql, "UPDATE t1 SET id= 3 WHERE name= 'updated'"); + myquery_r(rc); + + myquery(mysql_query(mysql, "drop table t1")); +} + + +/* Store result processing */ + +static void client_store_result() +{ + MYSQL_RES *result; + int rc; + + myheader("client_store_result"); + + rc= mysql_query(mysql, "SELECT * FROM t1"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + (void) my_process_result_set(result); + mysql_free_result(result); +} + + +/* Fetch the results */ + +static void client_use_result() +{ + MYSQL_RES *result; + int rc; + myheader("client_use_result"); + + rc= mysql_query(mysql, "SELECT * FROM t1"); + myquery(rc); + + /* get the result */ + result= mysql_use_result(mysql); + mytest(result); + + (void) my_process_result_set(result); + mysql_free_result(result); +} + + +/* Query processing */ + +static void test_debug_example() +{ + int rc; + MYSQL_RES *result; + + myheader("test_debug_example"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_debug_example"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_debug_example(" + "id INT PRIMARY KEY AUTO_INCREMENT, " + "name VARCHAR(20), xxx INT)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_debug_example (name) " + "VALUES ('mysql')"); + myquery(rc); + + rc= mysql_query(mysql, "UPDATE test_debug_example SET name='updated' " + "WHERE name='deleted'"); + myquery(rc); + + rc= mysql_query(mysql, "SELECT * FROM test_debug_example where name='mysql'"); + myquery(rc); + + result= mysql_use_result(mysql); + mytest(result); + + (void) my_process_result_set(result); + mysql_free_result(result); + + rc= mysql_query(mysql, "DROP TABLE test_debug_example"); + myquery(rc); +} + + +/* Test autocommit feature for BDB tables */ + +static void test_tran_bdb() +{ + MYSQL_RES *result; + MYSQL_ROW row; + int rc; + + myheader("test_tran_bdb"); + + /* set AUTOCOMMIT to OFF */ + rc= mysql_autocommit(mysql, FALSE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS my_demo_transaction"); + myquery(rc); + + + /* create the table 'mytran_demo' of type BDB' or 'InnoDB' */ + rc= mysql_query(mysql, "CREATE TABLE my_demo_transaction( " + "col1 int , col2 varchar(30)) ENGINE= BDB"); + myquery(rc); + + /* insert a row and commit the transaction */ + rc= mysql_query(mysql, "INSERT INTO my_demo_transaction VALUES(10, 'venu')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + /* now insert the second row, and roll back the transaction */ + rc= mysql_query(mysql, "INSERT INTO my_demo_transaction VALUES(20, 'mysql')"); + myquery(rc); + + rc= mysql_rollback(mysql); + myquery(rc); + + /* delete first row, and roll it back */ + rc= mysql_query(mysql, "DELETE FROM my_demo_transaction WHERE col1= 10"); + myquery(rc); + + rc= mysql_rollback(mysql); + myquery(rc); + + /* test the results now, only one row should exist */ + rc= mysql_query(mysql, "SELECT * FROM my_demo_transaction"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + (void) my_process_result_set(result); + mysql_free_result(result); + + /* test the results now, only one row should exist */ + rc= mysql_query(mysql, "SELECT * FROM my_demo_transaction"); + myquery(rc); + + /* get the result */ + result= mysql_use_result(mysql); + mytest(result); + + row= mysql_fetch_row(result); + mytest(row); + + row= mysql_fetch_row(result); + mytest_r(row); + + mysql_free_result(result); + mysql_autocommit(mysql, TRUE); +} + + +/* Test autocommit feature for InnoDB tables */ + +static void test_tran_innodb() +{ + MYSQL_RES *result; + MYSQL_ROW row; + int rc; + + myheader("test_tran_innodb"); + + /* set AUTOCOMMIT to OFF */ + rc= mysql_autocommit(mysql, FALSE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS my_demo_transaction"); + myquery(rc); + + /* create the table 'mytran_demo' of type BDB' or 'InnoDB' */ + rc= mysql_query(mysql, "CREATE TABLE my_demo_transaction(col1 int, " + "col2 varchar(30)) ENGINE= InnoDB"); + myquery(rc); + + /* insert a row and commit the transaction */ + rc= mysql_query(mysql, "INSERT INTO my_demo_transaction VALUES(10, 'venu')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + /* now insert the second row, and roll back the transaction */ + rc= mysql_query(mysql, "INSERT INTO my_demo_transaction VALUES(20, 'mysql')"); + myquery(rc); + + rc= mysql_rollback(mysql); + myquery(rc); + + /* delete first row, and roll it back */ + rc= mysql_query(mysql, "DELETE FROM my_demo_transaction WHERE col1= 10"); + myquery(rc); + + rc= mysql_rollback(mysql); + myquery(rc); + + /* test the results now, only one row should exist */ + rc= mysql_query(mysql, "SELECT * FROM my_demo_transaction"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + (void) my_process_result_set(result); + mysql_free_result(result); + + /* test the results now, only one row should exist */ + rc= mysql_query(mysql, "SELECT * FROM my_demo_transaction"); + myquery(rc); + + /* get the result */ + result= mysql_use_result(mysql); + mytest(result); + + row= mysql_fetch_row(result); + mytest(row); + + row= mysql_fetch_row(result); + mytest_r(row); + + mysql_free_result(result); + mysql_autocommit(mysql, TRUE); +} + + +/* Test for BUG#7242 */ + +static void test_prepare_insert_update() +{ + MYSQL_STMT *stmt; + int rc; + int i; + const char *testcase[]= { + "CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B))", + "INSERT t1 VALUES (1,2,10), (3,4,20)", + "INSERT t1 VALUES (5,6,30), (7,4,40), (8,9,60) ON DUPLICATE KEY UPDATE c=c+100", + "SELECT * FROM t1", + "INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0", + "SELECT * FROM t1", + "INSERT t1 VALUES (2,1,11), (7,4,40) ON DUPLICATE KEY UPDATE c=c+VALUES(a)", + NULL}; + const char **cur_query; + + myheader("test_prepare_insert_update"); + + for (cur_query= testcase; *cur_query; cur_query++) + { + char query[MAX_TEST_QUERY_LENGTH]; + printf("\nRunning query: %s", *cur_query); + strmov(query, *cur_query); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 0); + rc= mysql_stmt_execute(stmt); + + check_execute(stmt, rc); + /* try the last query several times */ + if (!cur_query[1]) + { + for (i=0; i < 3;i++) + { + printf("\nExecuting last statement again"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + } + mysql_stmt_close(stmt); + } + + rc= mysql_commit(mysql); + myquery(rc); +} + + +/* Test simple prepares of all DML statements */ + +static void test_prepare_simple() +{ + MYSQL_STMT *stmt; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_prepare_simple"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_simple"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_prepare_simple(" + "id int, name varchar(50))"); + myquery(rc); + + /* insert */ + strmov(query, "INSERT INTO test_prepare_simple VALUES(?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + mysql_stmt_close(stmt); + + /* update */ + strmov(query, "UPDATE test_prepare_simple SET id=? " + "WHERE id=? AND CONVERT(name USING utf8)= ?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 3); + mysql_stmt_close(stmt); + + /* delete */ + strmov(query, "DELETE FROM test_prepare_simple WHERE id=10"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 0); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_close(stmt); + + /* delete */ + strmov(query, "DELETE FROM test_prepare_simple WHERE id=?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 1); + + mysql_stmt_close(stmt); + + /* select */ + strmov(query, "SELECT * FROM test_prepare_simple WHERE id=? " + "AND CONVERT(name USING utf8)= ?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + mysql_stmt_close(stmt); + + /* show create */ + strmov(query, "SHOW CREATE TABLE test_prepare_simple"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + DIE_UNLESS(mysql_stmt_field_count(stmt) == 2); + mysql_stmt_close(stmt); + + /* show create database */ + strmov(query, "SHOW CREATE DATABASE test"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + DIE_UNLESS(mysql_stmt_field_count(stmt) == 2); + mysql_stmt_close(stmt); + + /* show grants */ + strmov(query, "SHOW GRANTS"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + DIE_UNLESS(mysql_stmt_field_count(stmt) == 1); + mysql_stmt_close(stmt); + + /* show slave status */ + strmov(query, "SHOW SLAVE STATUS"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + DIE_UNLESS(mysql_stmt_field_count(stmt) == 54); + mysql_stmt_close(stmt); + + /* show master status */ + strmov(query, "SHOW MASTER STATUS"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + DIE_UNLESS(mysql_stmt_field_count(stmt) == 4); + mysql_stmt_close(stmt); + + /* show create procedure */ + strmov(query, "SHOW CREATE PROCEDURE e1;"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + DIE_UNLESS(mysql_stmt_field_count(stmt) == 6); + mysql_stmt_close(stmt); + + /* show create function */ + strmov(query, "SHOW CREATE FUNCTION e1;"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + DIE_UNLESS(mysql_stmt_field_count(stmt) == 6); + mysql_stmt_close(stmt); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); +} + +/************************************************************************/ + +#define FILE_PATH_SIZE 4096 + +char mct_log_file_path[FILE_PATH_SIZE]; +FILE *mct_log_file= NULL; + +void mct_start_logging(const char *test_case_name) +{ + const char *tmp_dir= getenv("MYSQL_TMP_DIR"); + + if (!tmp_dir) + { + printf("Warning: MYSQL_TMP_DIR is not set. Logging is disabled.\n"); + return; + } + + if (mct_log_file) + { + printf("Warning: can not start logging for test case '%s' " + "because log is already open\n", + (const char *) test_case_name); + return; + } + + /* + Path is: <tmp_dir>/<test_case_name>.out.log + 10 is length of '/' + '.out.log' + \0 + */ + + if (strlen(tmp_dir) + strlen(test_case_name) + 10 > FILE_PATH_SIZE) + { + printf("Warning: MYSQL_TMP_DIR is too long. Logging is disabled.\n"); + return; + } + + my_snprintf(mct_log_file_path, FILE_PATH_SIZE, + "%s/%s.out.log", + (const char *) tmp_dir, + (const char *) test_case_name); + + mct_log_file= my_fopen(mct_log_file_path, O_WRONLY | O_BINARY, MYF(MY_WME)); + + if (!mct_log_file) + { + printf("Warning: can not open log file (%s): %s. Logging is disabled.\n", + (const char *) mct_log_file_path, + (const char *) strerror(errno)); + return; + } +} + +void mct_log(const char *format, ...) +{ + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + + if (mct_log_file) + { + va_list args; + va_start(args, format); + vfprintf(mct_log_file, format, args); + va_end(args); + } +} + +void mct_close_log() +{ + if (!mct_log_file) + return; + + my_fclose(mct_log_file, MYF(0)); + mct_log_file= NULL; +} + +#define WL4435_NUM_PARAMS 10 +#define WL4435_STRING_SIZE 30 + +static void test_wl4435() +{ + MYSQL_STMT *stmt; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + char str_data[20][WL4435_STRING_SIZE]; + double dbl_data[20]; + char dec_data[20][WL4435_STRING_SIZE]; + int int_data[20]; + ulong str_length= WL4435_STRING_SIZE; + my_bool is_null; + MYSQL_BIND ps_params[WL4435_NUM_PARAMS]; + + int exec_counter; + + myheader("test_wl4435"); + mct_start_logging("test_wl4435"); + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p2"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t2"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1(a1 INT, a2 CHAR(32), " + " a3 DOUBLE(4, 2), a4 DECIMAL(3, 1))"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2(b0 INT, b1 INT, b2 CHAR(32), " + " b3 DOUBLE(4, 2), b4 DECIMAL(3, 1))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES" + "(1, '11', 12.34, 56.7), " + "(2, '12', 56.78, 90.1), " + "(3, '13', 23.45, 67.8)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t2 VALUES" + "(100, 10, '110', 70.70, 10.1), " + "(200, 20, '120', 80.80, 20.2), " + "(300, 30, '130', 90.90, 30.3)"); + myquery(rc); + + rc= mysql_query(mysql, + "CREATE PROCEDURE p1(" + " IN v0 INT, " + " OUT v_str_1 CHAR(32), " + " OUT v_dbl_1 DOUBLE(4, 2), " + " OUT v_dec_1 DECIMAL(6, 3), " + " OUT v_int_1 INT, " + " IN v1 INT, " + " INOUT v_str_2 CHAR(64), " + " INOUT v_dbl_2 DOUBLE(5, 3), " + " INOUT v_dec_2 DECIMAL(7, 4), " + " INOUT v_int_2 INT)" + "BEGIN " + " SET v0 = -1; " + " SET v1 = -1; " + " SET v_str_1 = 'test_1'; " + " SET v_dbl_1 = 12.34; " + " SET v_dec_1 = 567.891; " + " SET v_int_1 = 2345; " + " SET v_str_2 = 'test_2'; " + " SET v_dbl_2 = 67.891; " + " SET v_dec_2 = 234.6789; " + " SET v_int_2 = 6789; " + " SELECT * FROM t1; " + " SELECT * FROM t2; " + "END"); + myquery(rc); + + rc= mysql_query(mysql, + "CREATE PROCEDURE p2(" + " IN i1 VARCHAR(255) CHARACTER SET koi8r, " + " OUT o1 VARCHAR(255) CHARACTER SET cp1251, " + " OUT o2 VARBINARY(255)) " + "BEGIN " + " SET o1 = i1; " + " SET o2 = i1; " + "END"); + myquery(rc); + + strmov(query, "CALL p1(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + /* Init PS-parameters. */ + + memset(str_data, 0, sizeof str_data); + memset(dbl_data, 0, sizeof dbl_data); + memset(dec_data, 0, sizeof dec_data); + memset(int_data, 0, sizeof int_data); + + bzero((char *) ps_params, sizeof (ps_params)); + + /* - v0 -- INT */ + + ps_params[0].buffer_type= MYSQL_TYPE_LONG; + ps_params[0].buffer= (char *) &int_data[0]; + ps_params[0].length= 0; + ps_params[0].is_null= 0; + + /* - v_str_1 -- CHAR(32) */ + + ps_params[1].buffer_type= MYSQL_TYPE_STRING; + ps_params[1].buffer= (char *) str_data[0]; + ps_params[1].buffer_length= WL4435_STRING_SIZE; + ps_params[1].length= &str_length; + ps_params[1].is_null= 0; + + /* - v_dbl_1 -- DOUBLE */ + + ps_params[2].buffer_type= MYSQL_TYPE_DOUBLE; + ps_params[2].buffer= (char *) &dbl_data[0]; + ps_params[2].length= 0; + ps_params[2].is_null= 0; + + /* - v_dec_1 -- DECIMAL */ + + ps_params[3].buffer_type= MYSQL_TYPE_NEWDECIMAL; + ps_params[3].buffer= (char *) dec_data[0]; + ps_params[3].buffer_length= WL4435_STRING_SIZE; + ps_params[3].length= 0; + ps_params[3].is_null= 0; + + /* - v_int_1 -- INT */ + + ps_params[4].buffer_type= MYSQL_TYPE_LONG; + ps_params[4].buffer= (char *) &int_data[0]; + ps_params[4].length= 0; + ps_params[4].is_null= 0; + + /* - v1 -- INT */ + + ps_params[5].buffer_type= MYSQL_TYPE_LONG; + ps_params[5].buffer= (char *) &int_data[0]; + ps_params[5].length= 0; + ps_params[5].is_null= 0; + + /* - v_str_2 -- CHAR(32) */ + + ps_params[6].buffer_type= MYSQL_TYPE_STRING; + ps_params[6].buffer= (char *) str_data[0]; + ps_params[6].buffer_length= WL4435_STRING_SIZE; + ps_params[6].length= &str_length; + ps_params[6].is_null= 0; + + /* - v_dbl_2 -- DOUBLE */ + + ps_params[7].buffer_type= MYSQL_TYPE_DOUBLE; + ps_params[7].buffer= (char *) &dbl_data[0]; + ps_params[7].length= 0; + ps_params[7].is_null= 0; + + /* - v_dec_2 -- DECIMAL */ + + ps_params[8].buffer_type= MYSQL_TYPE_DECIMAL; + ps_params[8].buffer= (char *) dec_data[0]; + ps_params[8].buffer_length= WL4435_STRING_SIZE; + ps_params[8].length= 0; + ps_params[8].is_null= 0; + + /* - v_int_2 -- INT */ + + ps_params[9].buffer_type= MYSQL_TYPE_LONG; + ps_params[9].buffer= (char *) &int_data[0]; + ps_params[9].length= 0; + ps_params[9].is_null= 0; + + /* Bind parameters. */ + + rc= mysql_stmt_bind_param(stmt, ps_params); + + /* Execute! */ + + for (exec_counter= 0; exec_counter < 3; ++exec_counter) + { + int i; + int num_fields; + MYSQL_BIND *rs_bind; + + mct_log("\nexec_counter: %d\n", (int) exec_counter); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + while (1) + { + MYSQL_FIELD *fields; + + MYSQL_RES *rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + fields= mysql_fetch_fields(rs_metadata); + + rs_bind= (MYSQL_BIND *) malloc(sizeof (MYSQL_BIND) * num_fields); + bzero(rs_bind, sizeof (MYSQL_BIND) * num_fields); + + mct_log("num_fields: %d\n", (int) num_fields); + + for (i = 0; i < num_fields; ++i) + { + mct_log(" - %d: name: '%s'/'%s'; table: '%s'/'%s'; " + "db: '%s'; catalog: '%s'; length: %d; max_length: %d; " + "type: %d; decimals: %d\n", + (int) i, + (const char *) fields[i].name, + (const char *) fields[i].org_name, + (const char *) fields[i].table, + (const char *) fields[i].org_table, + (const char *) fields[i].db, + (const char *) fields[i].catalog, + (int) fields[i].length, + (int) fields[i].max_length, + (int) fields[i].type, + (int) fields[i].decimals); + + rs_bind[i].buffer_type= fields[i].type; + rs_bind[i].is_null= &is_null; + + switch (fields[i].type) + { + case MYSQL_TYPE_LONG: + rs_bind[i].buffer= (char *) &(int_data[i]); + rs_bind[i].buffer_length= sizeof (int_data); + break; + + case MYSQL_TYPE_STRING: + rs_bind[i].buffer= (char *) str_data[i]; + rs_bind[i].buffer_length= WL4435_STRING_SIZE; + rs_bind[i].length= &str_length; + break; + + case MYSQL_TYPE_DOUBLE: + rs_bind[i].buffer= (char *) &dbl_data[i]; + rs_bind[i].buffer_length= sizeof (dbl_data); + break; + + case MYSQL_TYPE_NEWDECIMAL: + rs_bind[i].buffer= (char *) dec_data[i]; + rs_bind[i].buffer_length= WL4435_STRING_SIZE; + rs_bind[i].length= &str_length; + break; + + default: + fprintf(stderr, "ERROR: unexpected type: %d.\n", fields[i].type); + exit(1); + } + } + + rc= mysql_stmt_bind_result(stmt, rs_bind); + check_execute(stmt, rc); + + mct_log("Data:\n"); + + while (1) + { + int rc= mysql_stmt_fetch(stmt); + + if (rc == 1 || rc == MYSQL_NO_DATA) + break; + + mct_log(" "); + + for (i = 0; i < num_fields; ++i) + { + switch (rs_bind[i].buffer_type) + { + case MYSQL_TYPE_LONG: + mct_log(" int: %ld;", + (long) *((int *) rs_bind[i].buffer)); + break; + + case MYSQL_TYPE_STRING: + mct_log(" str: '%s';", + (char *) rs_bind[i].buffer); + break; + + case MYSQL_TYPE_DOUBLE: + mct_log(" dbl: %lf;", + (double) *((double *) rs_bind[i].buffer)); + break; + + case MYSQL_TYPE_NEWDECIMAL: + mct_log(" dec: '%s';", + (char *) rs_bind[i].buffer); + break; + + default: + printf(" unexpected type (%d)\n", + rs_bind[i].buffer_type); + } + } + mct_log("\n"); + } + + mct_log("EOF\n"); + + rc= mysql_stmt_next_result(stmt); + mct_log("mysql_stmt_next_result(): %d; field_count: %d\n", + (int) rc, (int) mysql->field_count); + + free(rs_bind); + mysql_free_result(rs_metadata); + + if (rc > 0) + { + printf("Error: %s (errno: %d)\n", + mysql_stmt_error(stmt), mysql_stmt_errno(stmt)); + DIE(rc > 0); + } + + if (rc) + break; + + if (!mysql->field_count) + { + /* This is the last OK-packet. No more resultsets. */ + break; + } + } + + } + + mysql_stmt_close(stmt); + + mct_close_log(); + + rc= mysql_commit(mysql); + myquery(rc); + + /* i18n part of test case. */ + + { + const char *str_koi8r= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5"; + const char *str_cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3"; + char o1_buffer[255]; + ulong o1_length; + char o2_buffer[255]; + ulong o2_length; + + MYSQL_BIND rs_bind[2]; + + strmov(query, "CALL p2(?, ?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + /* Init PS-parameters. */ + + bzero((char *) ps_params, sizeof (ps_params)); + + ps_params[0].buffer_type= MYSQL_TYPE_STRING; + ps_params[0].buffer= (char *) str_koi8r; + ps_params[0].buffer_length= strlen(str_koi8r); + + ps_params[1].buffer_type= MYSQL_TYPE_STRING; + ps_params[1].buffer= o1_buffer; + ps_params[1].buffer_length= 0; + + ps_params[2].buffer_type= MYSQL_TYPE_STRING; + ps_params[2].buffer= o2_buffer; + ps_params[2].buffer_length= 0; + + /* Bind parameters. */ + + rc= mysql_stmt_bind_param(stmt, ps_params); + check_execute(stmt, rc); + + /* Prevent converting to character_set_results. */ + + rc= mysql_query(mysql, "SET NAMES binary"); + myquery(rc); + + /* Execute statement. */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* Bind result. */ + + bzero(rs_bind, sizeof (rs_bind)); + + rs_bind[0].buffer_type= MYSQL_TYPE_STRING; + rs_bind[0].buffer= o1_buffer; + rs_bind[0].buffer_length= sizeof (o1_buffer); + rs_bind[0].length= &o1_length; + + rs_bind[1].buffer_type= MYSQL_TYPE_BLOB; + rs_bind[1].buffer= o2_buffer; + rs_bind[1].buffer_length= sizeof (o2_buffer); + rs_bind[1].length= &o2_length; + + rc= mysql_stmt_bind_result(stmt, rs_bind); + check_execute(stmt, rc); + + /* Fetch result. */ + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + /* Check result. */ + + DIE_UNLESS(o1_length == strlen(str_cp1251)); + DIE_UNLESS(o2_length == strlen(str_koi8r)); + DIE_UNLESS(!memcmp(o1_buffer, str_cp1251, o1_length)); + DIE_UNLESS(!memcmp(o2_buffer, str_koi8r, o2_length)); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_next_result(stmt); + DIE_UNLESS(rc == 0 && mysql->field_count == 0); + + mysql_stmt_close(stmt); + + rc= mysql_commit(mysql); + myquery(rc); + } +} + +static void test_wl4435_2() +{ + MYSQL_STMT *stmt; + int i; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_wl4435_2"); + mct_start_logging("test_wl4435_2"); + + /* + Do a few iterations so that we catch any problem with incorrect + handling/flushing prepared statement results. + */ + + for (i= 0; i < 10; ++i) + { + /* + Prepare a procedure. That can be moved out of the loop, but it was + left in the loop for the sake of having as many statements as + possible. + */ + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, + "CREATE PROCEDURE p1()" + "BEGIN " + " SELECT 1; " + " SELECT 2, 3 UNION SELECT 4, 5; " + " SELECT 6, 7, 8; " + "END"); + myquery(rc); + + /* Invoke a procedure, that returns several result sets. */ + + strmov(query, "CALL p1()"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + /* Execute! */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* Flush all the results. */ + + mysql_stmt_close(stmt); + + /* Clean up. */ + rc= mysql_commit(mysql); + myquery(rc); + + rc= mysql_query(mysql, "DROP PROCEDURE p1"); + myquery(rc); + } + mct_close_log(); +} + + +#define WL4435_TEST(sql_type, sql_value, \ + c_api_in_type, c_api_out_type, \ + c_type, c_type_ext, \ + printf_args, assert_condition) \ +\ + do { \ + int rc; \ + MYSQL_STMT *ps; \ + MYSQL_BIND psp; \ + MYSQL_RES *rs_metadata; \ + MYSQL_FIELD *fields; \ + c_type pspv c_type_ext; \ + my_bool psp_null= FALSE; \ + \ + bzero(&pspv, sizeof (pspv)); \ + \ + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); \ + myquery(rc); \ + \ + rc= mysql_query(mysql, \ + "CREATE PROCEDURE p1(OUT v " sql_type ") SET v = " sql_value ";"); \ + myquery(rc); \ + \ + ps = mysql_simple_prepare(mysql, "CALL p1(?)"); \ + check_stmt(ps); \ + \ + bzero(&psp, sizeof (psp)); \ + psp.buffer_type= c_api_in_type; \ + psp.is_null= &psp_null; \ + psp.buffer= (char *) &pspv; \ + psp.buffer_length= sizeof (psp); \ + \ + rc= mysql_stmt_bind_param(ps, &psp); \ + check_execute(ps, rc); \ + \ + rc= mysql_stmt_execute(ps); \ + check_execute(ps, rc); \ + \ + DIE_UNLESS(mysql->server_status & SERVER_PS_OUT_PARAMS); \ + DIE_UNLESS(mysql_stmt_field_count(ps) == 1); \ + \ + rs_metadata= mysql_stmt_result_metadata(ps); \ + fields= mysql_fetch_fields(rs_metadata); \ + mysql_free_result(rs_metadata); \ + \ + rc= mysql_stmt_bind_result(ps, &psp); \ + check_execute(ps, rc); \ + \ + rc= mysql_stmt_fetch(ps); \ + DIE_UNLESS(rc == 0); \ + \ + DIE_UNLESS(fields[0].type == c_api_out_type); \ + printf printf_args; \ + printf("; in type: %d; out type: %d\n", \ + (int) c_api_in_type, (int) c_api_out_type); \ + \ + rc= mysql_stmt_fetch(ps); \ + DIE_UNLESS(rc == MYSQL_NO_DATA); \ + \ + rc= mysql_stmt_next_result(ps); \ + DIE_UNLESS(rc == 0); \ + \ + mysql_stmt_free_result(ps); \ + mysql_stmt_close(ps); \ + \ + DIE_UNLESS(assert_condition); \ + \ + } while (0) + +static void test_wl4435_3() +{ + char tmp[255]; + + memset(tmp, 0, sizeof tmp); + puts(""); + + /* + // The following types are not supported: + // - ENUM + // - SET + // + // The following types are supported but can not be used for + // OUT-parameters: + // - MEDIUMINT; + // - BIT(..); + // + // The problem is that those types are not supported for IN-parameters, + // and OUT-parameters should be bound as IN-parameters before execution. + // + // The following types should not be used: + // - MYSQL_TYPE_YEAR (use MYSQL_TYPE_SHORT instead); + // - MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB + // (use MYSQL_TYPE_BLOB instead); + */ + + WL4435_TEST("TINYINT", "127", + MYSQL_TYPE_TINY, MYSQL_TYPE_TINY, + char, , + (" - TINYINT / char / MYSQL_TYPE_TINY:\t\t\t %d", (int) pspv), + pspv == 127); + + WL4435_TEST("SMALLINT", "32767", + MYSQL_TYPE_SHORT, MYSQL_TYPE_SHORT, + short, , + (" - SMALLINT / short / MYSQL_TYPE_SHORT:\t\t %d", (int) pspv), + pspv == 32767); + + WL4435_TEST("INT", "2147483647", + MYSQL_TYPE_LONG, MYSQL_TYPE_LONG, + int, , + (" - INT / int / MYSQL_TYPE_LONG:\t\t\t %d", pspv), + pspv == 2147483647l); + + WL4435_TEST("BIGINT", "9223372036854775807", + MYSQL_TYPE_LONGLONG, MYSQL_TYPE_LONGLONG, + long long, , + (" - BIGINT / long long / MYSQL_TYPE_LONGLONG:\t\t %lld", pspv), + pspv == 9223372036854775807ll); + + WL4435_TEST("TIMESTAMP", "'2007-11-18 15:01:02'", + MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_TIMESTAMP, + MYSQL_TIME, , + (" - TIMESTAMP / MYSQL_TIME / MYSQL_TYPE_TIMESTAMP:\t " + "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", + (int) pspv.year, (int) pspv.month, (int) pspv.day, + (int) pspv.hour, (int) pspv.minute, (int) pspv.second), + pspv.year == 2007 && pspv.month == 11 && pspv.day == 18 && + pspv.hour == 15 && pspv.minute == 1 && pspv.second == 2); + + WL4435_TEST("DATETIME", "'1234-11-12 12:34:59'", + MYSQL_TYPE_DATETIME, MYSQL_TYPE_DATETIME, + MYSQL_TIME, , + (" - DATETIME / MYSQL_TIME / MYSQL_TYPE_DATETIME:\t " + "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", + (int) pspv.year, (int) pspv.month, (int) pspv.day, + (int) pspv.hour, (int) pspv.minute, (int) pspv.second), + pspv.year == 1234 && pspv.month == 11 && pspv.day == 12 && + pspv.hour == 12 && pspv.minute == 34 && pspv.second == 59); + + WL4435_TEST("TIME", "'123:45:01'", + MYSQL_TYPE_TIME, MYSQL_TYPE_TIME, + MYSQL_TIME, , + (" - TIME / MYSQL_TIME / MYSQL_TYPE_TIME:\t\t " + "%.3d:%.2d:%.2d", + (int) pspv.hour, (int) pspv.minute, (int) pspv.second), + pspv.hour == 123 && pspv.minute == 45 && pspv.second == 1); + + WL4435_TEST("DATE", "'1234-11-12'", + MYSQL_TYPE_DATE, MYSQL_TYPE_DATE, + MYSQL_TIME, , + (" - DATE / MYSQL_TIME / MYSQL_TYPE_DATE:\t\t " + "%.4d-%.2d-%.2d", + (int) pspv.year, (int) pspv.month, (int) pspv.day), + pspv.year == 1234 && pspv.month == 11 && pspv.day == 12); + + WL4435_TEST("YEAR", "'2010'", + MYSQL_TYPE_SHORT, MYSQL_TYPE_YEAR, + short, , + (" - YEAR / short / MYSQL_TYPE_SHORT:\t\t\t %.4d", (int) pspv), + pspv == 2010); + + WL4435_TEST("FLOAT(7, 4)", "123.4567", + MYSQL_TYPE_FLOAT, MYSQL_TYPE_FLOAT, + float, , + (" - FLOAT / float / MYSQL_TYPE_FLOAT:\t\t\t %g", (double) pspv), + pspv - 123.4567 < 0.0001); + + WL4435_TEST("DOUBLE(8, 5)", "123.45678", + MYSQL_TYPE_DOUBLE, MYSQL_TYPE_DOUBLE, + double, , + (" - DOUBLE / double / MYSQL_TYPE_DOUBLE:\t\t %g", (double) pspv), + pspv - 123.45678 < 0.00001); + + WL4435_TEST("DECIMAL(9, 6)", "123.456789", + MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_NEWDECIMAL, + char, [255], + (" - DECIMAL / char[] / MYSQL_TYPE_NEWDECIMAL:\t\t '%s'", (char *) pspv), + !strcmp(pspv, "123.456789")); + + WL4435_TEST("CHAR(32)", "REPEAT('C', 16)", + MYSQL_TYPE_STRING, MYSQL_TYPE_STRING, + char, [255], + (" - CHAR(32) / char[] / MYSQL_TYPE_STRING:\t\t '%s'", (char *) pspv), + !strcmp(pspv, "CCCCCCCCCCCCCCCC")); + + WL4435_TEST("VARCHAR(32)", "REPEAT('V', 16)", + MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING, + char, [255], + (" - VARCHAR(32) / char[] / MYSQL_TYPE_VAR_STRING:\t '%s'", (char *) pspv), + !strcmp(pspv, "VVVVVVVVVVVVVVVV")); + + WL4435_TEST("TINYTEXT", "REPEAT('t', 16)", + MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - TINYTEXT / char[] / MYSQL_TYPE_TINY_BLOB:\t\t '%s'", (char *) pspv), + !strcmp(pspv, "tttttttttttttttt")); + + WL4435_TEST("TEXT", "REPEAT('t', 16)", + MYSQL_TYPE_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - TEXT / char[] / MYSQL_TYPE_BLOB:\t\t\t '%s'", (char *) pspv), + !strcmp(pspv, "tttttttttttttttt")); + + WL4435_TEST("MEDIUMTEXT", "REPEAT('t', 16)", + MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - MEDIUMTEXT / char[] / MYSQL_TYPE_MEDIUM_BLOB:\t '%s'", (char *) pspv), + !strcmp(pspv, "tttttttttttttttt")); + + WL4435_TEST("LONGTEXT", "REPEAT('t', 16)", + MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - LONGTEXT / char[] / MYSQL_TYPE_LONG_BLOB:\t\t '%s'", (char *) pspv), + !strcmp(pspv, "tttttttttttttttt")); + + WL4435_TEST("BINARY(32)", "REPEAT('\1', 16)", + MYSQL_TYPE_STRING, MYSQL_TYPE_STRING, + char, [255], + (" - BINARY(32) / char[] / MYSQL_TYPE_STRING:\t\t '%s'", (char *) pspv), + memset(tmp, 1, 16) && !memcmp(tmp, pspv, 16)); + + WL4435_TEST("VARBINARY(32)", "REPEAT('\1', 16)", + MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING, + char, [255], + (" - VARBINARY(32) / char[] / MYSQL_TYPE_VAR_STRING:\t '%s'", (char *) pspv), + memset(tmp, 1, 16) && !memcmp(tmp, pspv, 16)); + + WL4435_TEST("TINYBLOB", "REPEAT('\2', 16)", + MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - TINYBLOB / char[] / MYSQL_TYPE_TINY_BLOB:\t\t '%s'", (char *) pspv), + memset(tmp, 2, 16) && !memcmp(tmp, pspv, 16)); + + WL4435_TEST("BLOB", "REPEAT('\2', 16)", + MYSQL_TYPE_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - BLOB / char[] / MYSQL_TYPE_BLOB:\t\t\t '%s'", (char *) pspv), + memset(tmp, 2, 16) && !memcmp(tmp, pspv, 16)); + + WL4435_TEST("MEDIUMBLOB", "REPEAT('\2', 16)", + MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - MEDIUMBLOB / char[] / MYSQL_TYPE_MEDIUM_BLOB:\t '%s'", (char *) pspv), + memset(tmp, 2, 16) && !memcmp(tmp, pspv, 16)); + + WL4435_TEST("LONGBLOB", "REPEAT('\2', 16)", + MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - LONGBLOB / char[] / MYSQL_TYPE_LONG_BLOB:\t\t '%s'", (char *) pspv), + memset(tmp, 2, 16) && !memcmp(tmp, pspv, 16)); +} + + +/* Test simple prepare field results */ + +static void test_prepare_field_result() +{ + MYSQL_STMT *stmt; + MYSQL_RES *result; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_prepare_field_result"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_field_result"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_prepare_field_result(int_c int, " + "var_c varchar(50), ts_c timestamp, " + "char_c char(4), date_c date, extra tinyint)"); + myquery(rc); + + /* insert */ + strmov(query, "SELECT int_c, var_c, date_c as date, ts_c, char_c FROM " + " test_prepare_field_result as t1 WHERE int_c=?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 1); + + result= mysql_stmt_result_metadata(stmt); + mytest(result); + + my_print_result_metadata(result); + + if (!opt_silent) + fprintf(stdout, "\n\n field attributes:\n"); + verify_prepare_field(result, 0, "int_c", "int_c", MYSQL_TYPE_LONG, + "t1", "test_prepare_field_result", current_db, 11, 0); + verify_prepare_field(result, 1, "var_c", "var_c", MYSQL_TYPE_VAR_STRING, + "t1", "test_prepare_field_result", current_db, 50, 0); + verify_prepare_field(result, 2, "date", "date_c", MYSQL_TYPE_DATE, + "t1", "test_prepare_field_result", current_db, 10, 0); + verify_prepare_field(result, 3, "ts_c", "ts_c", MYSQL_TYPE_TIMESTAMP, + "t1", "test_prepare_field_result", current_db, 19, 0); + verify_prepare_field(result, 4, "char_c", "char_c", + (mysql_get_server_version(mysql) <= 50000 ? + MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING), + "t1", "test_prepare_field_result", current_db, 4, 0); + + verify_field_count(result, 5); + mysql_free_result(result); + mysql_stmt_close(stmt); +} + + +/* Test simple prepare field results */ + +static void test_prepare_syntax() +{ + MYSQL_STMT *stmt; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_prepare_syntax"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_syntax"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_prepare_syntax(" + "id int, name varchar(50), extra int)"); + myquery(rc); + + strmov(query, "INSERT INTO test_prepare_syntax VALUES(?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt_r(stmt); + + strmov(query, "SELECT id, name FROM test_prepare_syntax WHERE id=? AND WHERE"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt_r(stmt); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); +} + + +/* Test a simple prepare */ + +static void test_prepare() +{ + MYSQL_STMT *stmt; + int rc, i; + int int_data, o_int_data; + char str_data[50], data[50]; + char tiny_data, o_tiny_data; + short small_data, o_small_data; + longlong big_data, o_big_data; + float real_data, o_real_data; + double double_data, o_double_data; + ulong length[7], len; + my_bool is_null[7]; + char llbuf[22]; + MYSQL_BIND my_bind[7]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_prepare"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS my_prepare"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE my_prepare(col1 tinyint, " + "col2 varchar(15), col3 int, " + "col4 smallint, col5 bigint, " + "col6 float, col7 double )"); + myquery(rc); + + /* insert by prepare */ + strxmov(query, "INSERT INTO my_prepare VALUES(?, ?, ?, ?, ?, ?, ?)", NullS); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 7); + + bzero((char*) my_bind, sizeof(my_bind)); + + /* tinyint */ + my_bind[0].buffer_type= MYSQL_TYPE_TINY; + my_bind[0].buffer= (void *)&tiny_data; + /* string */ + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void *)str_data; + my_bind[1].buffer_length= 1000; /* Max string length */ + /* integer */ + my_bind[2].buffer_type= MYSQL_TYPE_LONG; + my_bind[2].buffer= (void *)&int_data; + /* short */ + my_bind[3].buffer_type= MYSQL_TYPE_SHORT; + my_bind[3].buffer= (void *)&small_data; + /* bigint */ + my_bind[4].buffer_type= MYSQL_TYPE_LONGLONG; + my_bind[4].buffer= (void *)&big_data; + /* float */ + my_bind[5].buffer_type= MYSQL_TYPE_FLOAT; + my_bind[5].buffer= (void *)&real_data; + /* double */ + my_bind[6].buffer_type= MYSQL_TYPE_DOUBLE; + my_bind[6].buffer= (void *)&double_data; + + for (i= 0; i < (int) array_elements(my_bind); i++) + { + my_bind[i].length= &length[i]; + my_bind[i].is_null= &is_null[i]; + is_null[i]= 0; + } + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + int_data= 320; + small_data= 1867; + big_data= 1000; + real_data= 2; + double_data= 6578.001; + + /* now, execute the prepared statement to insert 10 records.. */ + for (tiny_data= 0; tiny_data < 100; tiny_data++) + { + length[1]= sprintf(str_data, "MySQL%d", int_data); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + int_data += 25; + small_data += 10; + big_data += 100; + real_data += 1; + double_data += 10.09; + } + + mysql_stmt_close(stmt); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); + + /* test the results now, only one row should exist */ + rc= my_stmt_result("SELECT * FROM my_prepare"); + DIE_UNLESS(tiny_data == (char) rc); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM my_prepare"); + check_stmt(stmt); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + /* get the result */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + o_int_data= 320; + o_small_data= 1867; + o_big_data= 1000; + o_real_data= 2; + o_double_data= 6578.001; + + /* now, execute the prepared statement to insert 10 records.. */ + for (o_tiny_data= 0; o_tiny_data < 100; o_tiny_data++) + { + len= sprintf(data, "MySQL%d", o_int_data); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + { + fprintf(stdout, "\n"); + fprintf(stdout, "\n\t tiny : %d (%lu)", tiny_data, length[0]); + fprintf(stdout, "\n\t short : %d (%lu)", small_data, length[3]); + fprintf(stdout, "\n\t int : %d (%lu)", int_data, length[2]); + fprintf(stdout, "\n\t big : %s (%lu)", llstr(big_data, llbuf), + length[4]); + + fprintf(stdout, "\n\t float : %f (%lu)", real_data, length[5]); + fprintf(stdout, "\n\t double : %f (%lu)", double_data, length[6]); + + fprintf(stdout, "\n\t str : %s (%lu)", str_data, length[1]); + } + + DIE_UNLESS(tiny_data == o_tiny_data); + DIE_UNLESS(is_null[0] == 0); + DIE_UNLESS(length[0] == 1); + + DIE_UNLESS(int_data == o_int_data); + DIE_UNLESS(length[2] == 4); + + DIE_UNLESS(small_data == o_small_data); + DIE_UNLESS(length[3] == 2); + + DIE_UNLESS(big_data == o_big_data); + DIE_UNLESS(length[4] == 8); + + DIE_UNLESS(real_data == o_real_data); + DIE_UNLESS(length[5] == 4); + + DIE_UNLESS(cmp_double(&double_data, &o_double_data)); + DIE_UNLESS(length[6] == 8); + + DIE_UNLESS(strcmp(data, str_data) == 0); + DIE_UNLESS(length[1] == len); + + o_int_data += 25; + o_small_data += 10; + o_big_data += 100; + o_real_data += 1; + o_double_data += 10.09; + } + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + +} + + +/* Test double comparision */ + +static void test_double_compare() +{ + MYSQL_STMT *stmt; + int rc; + char real_data[10], tiny_data; + double double_data; + MYSQL_RES *result; + MYSQL_BIND my_bind[3]; + ulong length[3]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_double_compare"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_double_compare"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_double_compare(col1 tinyint, " + " col2 float, col3 double )"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_double_compare " + "VALUES (1, 10.2, 34.5)"); + myquery(rc); + + strmov(query, "UPDATE test_double_compare SET col1=100 " + "WHERE col1 = ? AND col2 = ? AND COL3 = ?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 3); + + /* Always bzero bind array because there can be internal members */ + bzero((char*) my_bind, sizeof(my_bind)); + + /* tinyint */ + my_bind[0].buffer_type= MYSQL_TYPE_TINY; + my_bind[0].buffer= (void *)&tiny_data; + + /* string->float */ + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void *)&real_data; + my_bind[1].buffer_length= sizeof(real_data); + my_bind[1].length= &length[1]; + length[1]= 10; + + /* double */ + my_bind[2].buffer_type= MYSQL_TYPE_DOUBLE; + my_bind[2].buffer= (void *)&double_data; + + tiny_data= 1; + memset(real_data, 0, sizeof real_data); + strmov(real_data, "10.2"); + double_data= 34.5; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_affected_rows(0); + + mysql_stmt_close(stmt); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); + + /* test the results now, only one row should exist */ + rc= mysql_query(mysql, "SELECT * FROM test_double_compare"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS((int)tiny_data == rc); + mysql_free_result(result); +} + + +/* Test simple null */ + +static void test_null() +{ + MYSQL_STMT *stmt; + int rc; + uint nData; + MYSQL_BIND my_bind[2]; + my_bool is_null[2]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_null"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_null"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_null(col1 int, col2 varchar(50))"); + myquery(rc); + + /* insert by prepare, wrong column name */ + strmov(query, "INSERT INTO test_null(col3, col2) VALUES(?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt_r(stmt); + + strmov(query, "INSERT INTO test_null(col1, col2) VALUES(?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].is_null= &is_null[0]; + is_null[0]= 1; + my_bind[1]= my_bind[0]; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + /* now, execute the prepared statement to insert 10 records.. */ + for (nData= 0; nData<10; nData++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + + /* Re-bind with MYSQL_TYPE_NULL */ + my_bind[0].buffer_type= MYSQL_TYPE_NULL; + is_null[0]= 0; /* reset */ + my_bind[1]= my_bind[0]; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + for (nData= 0; nData<10; nData++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + + mysql_stmt_close(stmt); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); + + nData*= 2; + rc= my_stmt_result("SELECT * FROM test_null");; + DIE_UNLESS((int) nData == rc); + + /* Fetch results */ + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&nData; /* this buffer won't be altered */ + my_bind[0].length= 0; + my_bind[1]= my_bind[0]; + my_bind[0].is_null= &is_null[0]; + my_bind[1].is_null= &is_null[1]; + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_null"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= 0; + is_null[0]= is_null[1]= 0; + while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + { + DIE_UNLESS(is_null[0]); + DIE_UNLESS(is_null[1]); + rc++; + is_null[0]= is_null[1]= 0; + } + DIE_UNLESS(rc == (int) nData); + mysql_stmt_close(stmt); +} + + +/* Test for NULL as PS parameter (BUG#3367, BUG#3371) */ + +static void test_ps_null_param() +{ + MYSQL_STMT *stmt; + int rc; + + MYSQL_BIND in_bind; + my_bool in_is_null; + long int in_long; + + MYSQL_BIND out_bind; + ulong out_length; + my_bool out_is_null; + char out_str_data[20]; + + const char *queries[]= {"select ?", "select ?+1", + "select col1 from test_ps_nulls where col1 <=> ?", + NULL + }; + const char **cur_query= queries; + + myheader("test_null_ps_param_in_result"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ps_nulls"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_ps_nulls(col1 int)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_ps_nulls values (1), (null)"); + myquery(rc); + + /* Always bzero all members of bind parameter */ + bzero((char*) &in_bind, sizeof(in_bind)); + bzero((char*) &out_bind, sizeof(out_bind)); + + in_bind.buffer_type= MYSQL_TYPE_LONG; + in_bind.is_null= &in_is_null; + in_bind.length= 0; + in_bind.buffer= (void *)&in_long; + in_is_null= 1; + in_long= 1; + + out_bind.buffer_type= MYSQL_TYPE_STRING; + out_bind.is_null= &out_is_null; + out_bind.length= &out_length; + out_bind.buffer= out_str_data; + out_bind.buffer_length= array_elements(out_str_data); + + /* Execute several queries, all returning NULL in result. */ + for(cur_query= queries; *cur_query; cur_query++) + { + char query[MAX_TEST_QUERY_LENGTH]; + strmov(query, *cur_query); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + verify_param_count(stmt, 1); + + rc= mysql_stmt_bind_param(stmt, &in_bind); + check_execute(stmt, rc); + rc= mysql_stmt_bind_result(stmt, &out_bind); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc != MYSQL_NO_DATA); + DIE_UNLESS(out_is_null); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + mysql_stmt_close(stmt); + } +} + + +/* Test fetch null */ + +static void test_fetch_null() +{ + MYSQL_STMT *stmt; + int rc; + int i, nData; + MYSQL_BIND my_bind[11]; + ulong length[11]; + my_bool is_null[11]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_fetch_null"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_fetch_null"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_fetch_null(" + " col1 tinyint, col2 smallint, " + " col3 int, col4 bigint, " + " col5 float, col6 double, " + " col7 date, col8 time, " + " col9 varbinary(10), " + " col10 varchar(50), " + " col11 char(20))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_fetch_null (col11) " + "VALUES (1000), (88), (389789)"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + /* fetch */ + bzero((char*) my_bind, sizeof(my_bind)); + for (i= 0; i < (int) array_elements(my_bind); i++) + { + my_bind[i].buffer_type= MYSQL_TYPE_LONG; + my_bind[i].is_null= &is_null[i]; + my_bind[i].length= &length[i]; + } + my_bind[i-1].buffer= (void *)&nData; /* Last column is not null */ + + strmov((char *)query , "SELECT * FROM test_fetch_null"); + + rc= my_stmt_result(query); + DIE_UNLESS(rc == 3); + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= 0; + while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + { + rc++; + for (i= 0; i < 10; i++) + { + if (!opt_silent) + fprintf(stdout, "\n data[%d] : %s", i, + is_null[i] ? "NULL" : "NOT NULL"); + DIE_UNLESS(is_null[i]); + } + if (!opt_silent) + fprintf(stdout, "\n data[%d]: %d", i, nData); + DIE_UNLESS(nData == 1000 || nData == 88 || nData == 389789); + DIE_UNLESS(is_null[i] == 0); + DIE_UNLESS(length[i] == 4); + } + DIE_UNLESS(rc == 3); + mysql_stmt_close(stmt); +} + + +/* Test simple select */ + +static void test_select_version() +{ + MYSQL_STMT *stmt; + int rc; + + myheader("test_select_version"); + + stmt= mysql_simple_prepare(mysql, "SELECT @@version"); + check_stmt(stmt); + + verify_param_count(stmt, 0); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + my_process_stmt_result(stmt); + mysql_stmt_close(stmt); +} + + +/* Test simple show */ + +static void test_select_show_table() +{ + MYSQL_STMT *stmt; + int rc, i; + + myheader("test_select_show_table"); + + stmt= mysql_simple_prepare(mysql, "SHOW TABLES FROM mysql"); + check_stmt(stmt); + + verify_param_count(stmt, 0); + + for (i= 1; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + + my_process_stmt_result(stmt); + mysql_stmt_close(stmt); +} + + +/* Test simple select to debug */ + +static void test_select_direct() +{ + int rc; + MYSQL_RES *result; + + myheader("test_select_direct"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_select(id int, id1 tinyint, " + " id2 float, " + " id3 double, " + " name varchar(50))"); + myquery(rc); + + /* insert a row and commit the transaction */ + rc= mysql_query(mysql, "INSERT INTO test_select VALUES(10, 5, 2.3, 4.5, 'venu')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + rc= mysql_query(mysql, "SELECT * FROM test_select"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + (void) my_process_result_set(result); + mysql_free_result(result); +} + + +/* Test simple select with prepare */ + +static void test_select_prepare() +{ + int rc; + MYSQL_STMT *stmt; + + myheader("test_select_prepare"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_select(id int, name varchar(50))"); + myquery(rc); + + /* insert a row and commit the transaction */ + rc= mysql_query(mysql, "INSERT INTO test_select VALUES(10, 'venu')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_select"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE test_select"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_select(id tinyint, id1 int, " + " id2 float, id3 float, " + " name varchar(50))"); + myquery(rc); + + /* insert a row and commit the transaction */ + rc= mysql_query(mysql, "INSERT INTO test_select(id, id1, id2, name) VALUES(10, 5, 2.3, 'venu')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_select"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + mysql_stmt_close(stmt); +} + + +/* Test simple select */ + +static void test_select() +{ + MYSQL_STMT *stmt; + int rc; + char szData[25]; + int nData= 1; + MYSQL_BIND my_bind[2]; + ulong length[2]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_select"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_select(id int, name varchar(50))"); + myquery(rc); + + /* insert a row and commit the transaction */ + rc= mysql_query(mysql, "INSERT INTO test_select VALUES(10, 'venu')"); + myquery(rc); + + /* now insert the second row, and roll back the transaction */ + rc= mysql_query(mysql, "INSERT INTO test_select VALUES(20, 'mysql')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + strmov(query, "SELECT * FROM test_select WHERE id= ? " + "AND CONVERT(name USING utf8) =?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + /* string data */ + nData= 10; + strmov(szData, (char *)"venu"); + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void *)szData; + my_bind[1].buffer_length= 4; + my_bind[1].length= &length[1]; + length[1]= 4; + + my_bind[0].buffer= (void *)&nData; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); +} + + +/* + Test for BUG#3420 ("select id1, value1 from t where id= ? or value= ?" + returns all rows in the table) +*/ + +static void test_ps_conj_select() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_BIND my_bind[2]; + int32 int_data; + char str_data[32]; + unsigned long str_length; + char query[MAX_TEST_QUERY_LENGTH]; + myheader("test_ps_conj_select"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 (id1 int(11) NOT NULL default '0', " + "value2 varchar(100), value1 varchar(100))"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1 values (1, 'hh', 'hh'), " + "(2, 'hh', 'hh'), (1, 'ii', 'ii'), (2, 'ii', 'ii')"); + myquery(rc); + + strmov(query, "SELECT id1, value1 from t1 where id1= ? or " + "CONVERT(value1 USING utf8)= ?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&int_data; + + my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + my_bind[1].buffer= (void *)str_data; + my_bind[1].buffer_length= array_elements(str_data); + my_bind[1].length= &str_length; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + int_data= 1; + strmov(str_data, "hh"); + str_length= strlen(str_data); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 3); + + mysql_stmt_close(stmt); +} + + +/* reads Qcache_hits from server and returns its value */ +static uint query_cache_hits(MYSQL *conn) +{ + MYSQL_RES *res; + MYSQL_ROW row; + int rc; + uint result; + + rc= mysql_query(conn, "show status like 'qcache_hits'"); + myquery(rc); + res= mysql_use_result(conn); + DIE_UNLESS(res); + + row= mysql_fetch_row(res); + DIE_UNLESS(row); + + result= atoi(row[1]); + mysql_free_result(res); + return result; +} + + +/* + utility for the next test; expects 3 rows in the result from a SELECT, + compares each row/field with an expected value. + */ +#define test_ps_query_cache_result(i1,s1,l1,i2,s2,l2,i3,s3,l3) \ + r_metadata= mysql_stmt_result_metadata(stmt); \ + DIE_UNLESS(r_metadata != NULL); \ + rc= mysql_stmt_fetch(stmt); \ + check_execute(stmt, rc); \ + if (!opt_silent) \ + fprintf(stdout, "\n row 1: %d, %s(%lu)", r_int_data, \ + r_str_data, r_str_length); \ + DIE_UNLESS((r_int_data == i1) && (r_str_length == l1) && \ + (strcmp(r_str_data, s1) == 0)); \ + rc= mysql_stmt_fetch(stmt); \ + check_execute(stmt, rc); \ + if (!opt_silent) \ + fprintf(stdout, "\n row 2: %d, %s(%lu)", r_int_data, \ + r_str_data, r_str_length); \ + DIE_UNLESS((r_int_data == i2) && (r_str_length == l2) && \ + (strcmp(r_str_data, s2) == 0)); \ + rc= mysql_stmt_fetch(stmt); \ + check_execute(stmt, rc); \ + if (!opt_silent) \ + fprintf(stdout, "\n row 3: %d, %s(%lu)", r_int_data, \ + r_str_data, r_str_length); \ + DIE_UNLESS((r_int_data == i3) && (r_str_length == l3) && \ + (strcmp(r_str_data, s3) == 0)); \ + rc= mysql_stmt_fetch(stmt); \ + DIE_UNLESS(rc == MYSQL_NO_DATA); \ + mysql_free_result(r_metadata); + + +/* + Check that query cache is available in server. +*/ +static my_bool is_query_cache_available() +{ + int rc; + MYSQL_RES *result; + MYSQL_ROW row; + int res= -1; + + rc= mysql_query(mysql, "SHOW VARIABLES LIKE 'have_query_cache'"); + myquery(rc); + + result= mysql_store_result(mysql); + DIE_UNLESS(result); + + row= mysql_fetch_row(result); + DIE_UNLESS(row != NULL); + if (strcmp(row[1], "YES") == 0) + res= 1; + else if (strcmp(row[1], "NO") == 0) + res= 0; + mysql_free_result(result); + + DIE_UNLESS(res == 0 || res == 1); + return res; +} + +/* + Test that prepared statements make use of the query cache just as normal + statements (BUG#735). +*/ +static void test_ps_query_cache() +{ + MYSQL *lmysql= mysql; + MYSQL_STMT *stmt; + int rc; + MYSQL_BIND p_bind[2],r_bind[2]; /* p: param bind; r: result bind */ + int32 p_int_data, r_int_data; + char p_str_data[32], r_str_data[32]; + unsigned long p_str_length, r_str_length; + MYSQL_RES *r_metadata; + char query[MAX_TEST_QUERY_LENGTH]; + uint hits1, hits2; + enum enum_test_ps_query_cache + { + /* + We iterate the same prepare/executes block, but have iterations where + we vary the query cache conditions. + */ + /* the query cache is enabled for the duration of prep&execs: */ + TEST_QCACHE_ON= 0, + /* + same but using a new connection (to see if qcache serves results from + the previous connection as it should): + */ + TEST_QCACHE_ON_WITH_OTHER_CONN, + /* + First border case: disables the query cache before prepare and + re-enables it before execution (to test if we have no bug then): + */ + TEST_QCACHE_OFF_ON, + /* + Second border case: enables the query cache before prepare and + disables it before execution: + */ + TEST_QCACHE_ON_OFF + }; + enum enum_test_ps_query_cache iteration; + + myheader("test_ps_query_cache"); + + if (! is_query_cache_available()) + { + fprintf(stdout, "Skipping test_ps_query_cache: Query cache not available.\n"); + return; + } + + rc= mysql_set_character_set(mysql, "utf8"); + myquery(rc); + + /* prepare the table */ + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 (id1 int(11) NOT NULL default '0', " + "value2 varchar(100), value1 varchar(100))"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1 values (1, 'hh', 'hh'), " + "(2, 'hh', 'hh'), (1, 'ii', 'ii'), (2, 'ii', 'ii')"); + myquery(rc); + + rc= mysql_query(mysql, + "set @save_query_cache_type=" + "@@global.query_cache_type," + "@save_query_cache_size=" + "@@global.query_cache_size"); + myquery(rc); + rc= mysql_query(lmysql, "set global query_cache_type=ON"); + myquery(rc); + rc= mysql_query(lmysql, "set local query_cache_type=ON"); + myquery(rc); + + for (iteration= TEST_QCACHE_ON; iteration <= TEST_QCACHE_ON_OFF; iteration++) + { + + switch (iteration) { + case TEST_QCACHE_ON: + case TEST_QCACHE_ON_OFF: + rc= mysql_query(lmysql, "set global query_cache_size=1000000"); + myquery(rc); + break; + case TEST_QCACHE_OFF_ON: + rc= mysql_query(lmysql, "set global query_cache_size=0"); + myquery(rc); + break; + case TEST_QCACHE_ON_WITH_OTHER_CONN: + if (!opt_silent) + fprintf(stdout, "\n Establishing a test connection ..."); + if (!(lmysql= mysql_client_init(NULL))) + { + printf("mysql_client_init() failed"); + DIE_UNLESS(0); + } + if (!(mysql_real_connect(lmysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + printf("connection failed"); + mysql_close(lmysql); + DIE_UNLESS(0); + } + rc= mysql_query(lmysql, "SET SQL_MODE=''"); + myquery(rc); + rc= mysql_set_character_set(lmysql, "utf8"); + myquery(rc); + + if (!opt_silent) + fprintf(stdout, "OK"); + break; + } + + strmov(query, "select id1, value1 from t1 where id1= ? or " + "CONVERT(value1 USING utf8)= ?"); + stmt= mysql_simple_prepare(lmysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + switch (iteration) { + case TEST_QCACHE_OFF_ON: + rc= mysql_query(lmysql, "set global query_cache_size=1000000"); + myquery(rc); + break; + case TEST_QCACHE_ON_OFF: + rc= mysql_query(lmysql, "set global query_cache_size=0"); + myquery(rc); + default: + break; + } + + bzero((char*) p_bind, sizeof(p_bind)); + p_bind[0].buffer_type= MYSQL_TYPE_LONG; + p_bind[0].buffer= (void *)&p_int_data; + p_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + p_bind[1].buffer= (void *)p_str_data; + p_bind[1].buffer_length= array_elements(p_str_data); + p_bind[1].length= &p_str_length; + + rc= mysql_stmt_bind_param(stmt, p_bind); + check_execute(stmt, rc); + + p_int_data= 1; + strmov(p_str_data, "hh"); + p_str_length= strlen(p_str_data); + + bzero((char*) r_bind, sizeof(r_bind)); + r_bind[0].buffer_type= MYSQL_TYPE_LONG; + r_bind[0].buffer= (void *)&r_int_data; + r_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + r_bind[1].buffer= (void *)r_str_data; + r_bind[1].buffer_length= array_elements(r_str_data); + r_bind[1].length= &r_str_length; + + rc= mysql_stmt_bind_result(stmt, r_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + test_ps_query_cache_result(1, "hh", 2, 2, "hh", 2, 1, "ii", 2); + + /* now retry with the same parameter values and see qcache hits */ + hits1= query_cache_hits(lmysql); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + test_ps_query_cache_result(1, "hh", 2, 2, "hh", 2, 1, "ii", 2); + hits2= query_cache_hits(lmysql); + switch(iteration) { + case TEST_QCACHE_ON_WITH_OTHER_CONN: + case TEST_QCACHE_ON: /* should have hit */ + DIE_UNLESS(hits2-hits1 == 1); + break; + case TEST_QCACHE_OFF_ON: + case TEST_QCACHE_ON_OFF: /* should not have hit */ + DIE_UNLESS(hits2-hits1 == 0); + break; + } + + /* now modify parameter values and see qcache hits */ + strmov(p_str_data, "ii"); + p_str_length= strlen(p_str_data); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + test_ps_query_cache_result(1, "hh", 2, 1, "ii", 2, 2, "ii", 2); + hits1= query_cache_hits(lmysql); + + switch(iteration) { + case TEST_QCACHE_ON: + case TEST_QCACHE_OFF_ON: + case TEST_QCACHE_ON_OFF: /* should not have hit */ + DIE_UNLESS(hits2-hits1 == 0); + break; + case TEST_QCACHE_ON_WITH_OTHER_CONN: /* should have hit */ + DIE_UNLESS(hits1-hits2 == 1); + break; + } + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + test_ps_query_cache_result(1, "hh", 2, 1, "ii", 2, 2, "ii", 2); + hits2= query_cache_hits(lmysql); + + mysql_stmt_close(stmt); + + switch(iteration) { + case TEST_QCACHE_ON: /* should have hit */ + DIE_UNLESS(hits2-hits1 == 1); + break; + case TEST_QCACHE_OFF_ON: + case TEST_QCACHE_ON_OFF: /* should not have hit */ + DIE_UNLESS(hits2-hits1 == 0); + break; + case TEST_QCACHE_ON_WITH_OTHER_CONN: /* should have hit */ + DIE_UNLESS(hits2-hits1 == 1); + break; + } + + } /* for(iteration=...) */ + + if (lmysql != mysql) + mysql_close(lmysql); + + rc= mysql_query(mysql, "set global query_cache_size=@save_query_cache_size"); + myquery(rc); + rc= mysql_query(mysql, "set global query_cache_type=@save_query_cache_type"); + myquery(rc); +} + + +/* Test BUG#1115 (incorrect string parameter value allocation) */ + +static void test_bug1115() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_BIND my_bind[1]; + ulong length[1]; + char szData[11]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_bug1115"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_select(\ +session_id char(9) NOT NULL, \ + a int(8) unsigned NOT NULL, \ + b int(5) NOT NULL, \ + c int(5) NOT NULL, \ + d datetime NOT NULL)"); + myquery(rc); + rc= mysql_query(mysql, "INSERT INTO test_select VALUES " + "(\"abc\", 1, 2, 3, 2003-08-30), " + "(\"abd\", 1, 2, 3, 2003-08-30), " + "(\"abf\", 1, 2, 3, 2003-08-30), " + "(\"abg\", 1, 2, 3, 2003-08-30), " + "(\"abh\", 1, 2, 3, 2003-08-30), " + "(\"abj\", 1, 2, 3, 2003-08-30), " + "(\"abk\", 1, 2, 3, 2003-08-30), " + "(\"abl\", 1, 2, 3, 2003-08-30), " + "(\"abq\", 1, 2, 3, 2003-08-30) "); + myquery(rc); + rc= mysql_query(mysql, "INSERT INTO test_select VALUES " + "(\"abw\", 1, 2, 3, 2003-08-30), " + "(\"abe\", 1, 2, 3, 2003-08-30), " + "(\"abr\", 1, 2, 3, 2003-08-30), " + "(\"abt\", 1, 2, 3, 2003-08-30), " + "(\"aby\", 1, 2, 3, 2003-08-30), " + "(\"abu\", 1, 2, 3, 2003-08-30), " + "(\"abi\", 1, 2, 3, 2003-08-30), " + "(\"abo\", 1, 2, 3, 2003-08-30), " + "(\"abp\", 1, 2, 3, 2003-08-30), " + "(\"abz\", 1, 2, 3, 2003-08-30), " + "(\"abx\", 1, 2, 3, 2003-08-30)"); + myquery(rc); + + strmov(query, "SELECT * FROM test_select WHERE " + "CONVERT(session_id USING utf8)= ?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 1); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + strmov(szData, (char *)"abc"); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)szData; + my_bind[0].buffer_length= 10; + my_bind[0].length= &length[0]; + length[0]= 3; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + strmov(szData, (char *)"venu"); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)szData; + my_bind[0].buffer_length= 10; + my_bind[0].length= &length[0]; + length[0]= 4; + my_bind[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 0); + + strmov(szData, (char *)"abc"); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)szData; + my_bind[0].buffer_length= 10; + my_bind[0].length= &length[0]; + length[0]= 3; + my_bind[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); +} + + +/* Test BUG#1180 (optimized away part of WHERE clause) */ + +static void test_bug1180() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_BIND my_bind[1]; + ulong length[1]; + char szData[11]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_select_bug"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_select(session_id char(9) NOT NULL)"); + myquery(rc); + rc= mysql_query(mysql, "INSERT INTO test_select VALUES (\"abc\")"); + myquery(rc); + + strmov(query, "SELECT * FROM test_select WHERE ?= \"1111\" and " + "session_id= \"abc\""); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 1); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + strmov(szData, (char *)"abc"); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)szData; + my_bind[0].buffer_length= 10; + my_bind[0].length= &length[0]; + length[0]= 3; + my_bind[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 0); + + strmov(szData, (char *)"1111"); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)szData; + my_bind[0].buffer_length= 10; + my_bind[0].length= &length[0]; + length[0]= 4; + my_bind[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + strmov(szData, (char *)"abc"); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)szData; + my_bind[0].buffer_length= 10; + my_bind[0].length= &length[0]; + length[0]= 3; + my_bind[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 0); + + mysql_stmt_close(stmt); +} + + +/* + Test BUG#1644 (Insertion of more than 3 NULL columns with parameter + binding fails) +*/ + +static void test_bug1644() +{ + MYSQL_STMT *stmt; + MYSQL_RES *result; + MYSQL_ROW row; + MYSQL_BIND my_bind[4]; + int num; + my_bool isnull; + int rc, i; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_bug1644"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS foo_dfr"); + myquery(rc); + + rc= mysql_query(mysql, + "CREATE TABLE foo_dfr(col1 int, col2 int, col3 int, col4 int);"); + myquery(rc); + + strmov(query, "INSERT INTO foo_dfr VALUES (?, ?, ?, ? )"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 4); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + num= 22; + isnull= 0; + for (i= 0 ; i < 4 ; i++) + { + my_bind[i].buffer_type= MYSQL_TYPE_LONG; + my_bind[i].buffer= (void *)# + my_bind[i].is_null= &isnull; + } + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + isnull= 1; + for (i= 0 ; i < 4 ; i++) + my_bind[i].is_null= &isnull; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + isnull= 0; + num= 88; + for (i= 0 ; i < 4 ; i++) + my_bind[i].is_null= &isnull; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "SELECT * FROM foo_dfr"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 3); + + mysql_data_seek(result, 0); + + row= mysql_fetch_row(result); + mytest(row); + for (i= 0 ; i < 4 ; i++) + { + DIE_UNLESS(strcmp(row[i], "22") == 0); + } + row= mysql_fetch_row(result); + mytest(row); + for (i= 0 ; i < 4 ; i++) + { + DIE_UNLESS(row[i] == 0); + } + row= mysql_fetch_row(result); + mytest(row); + for (i= 0 ; i < 4 ; i++) + { + DIE_UNLESS(strcmp(row[i], "88") == 0); + } + row= mysql_fetch_row(result); + mytest_r(row); + + mysql_free_result(result); +} + + +/* Test simple select show */ + +static void test_select_show() +{ + MYSQL_STMT *stmt; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_select_show"); + + mysql_autocommit(mysql, TRUE); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_show"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_show(id int(4) NOT NULL primary " + " key, name char(2))"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "show columns from test_show"); + check_stmt(stmt); + + verify_param_count(stmt, 0); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "show tables from mysql like ?"); + check_stmt_r(stmt); + + strxmov(query, "show tables from ", current_db, " like \'test_show\'", NullS); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "describe test_show"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "show keys from test_show"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + mysql_stmt_close(stmt); +} + + +/* Test simple update */ + +static void test_simple_update() +{ + MYSQL_STMT *stmt; + int rc; + char szData[25]; + int nData= 1; + MYSQL_RES *result; + MYSQL_BIND my_bind[2]; + ulong length[2]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_simple_update"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_update"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_update(col1 int, " + " col2 varchar(50), col3 int )"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_update VALUES(1, 'MySQL', 100)"); + myquery(rc); + + verify_affected_rows(1); + + rc= mysql_commit(mysql); + myquery(rc); + + /* insert by prepare */ + strmov(query, "UPDATE test_update SET col2= ? WHERE col1= ?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + nData= 1; + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= szData; /* string data */ + my_bind[0].buffer_length= sizeof(szData); + my_bind[0].length= &length[0]; + length[0]= sprintf(szData, "updated-data"); + + my_bind[1].buffer= (void *) &nData; + my_bind[1].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + verify_affected_rows(1); + + mysql_stmt_close(stmt); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); + + /* test the results now, only one row should exist */ + rc= mysql_query(mysql, "SELECT * FROM test_update"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); +} + + +/* Test simple long data handling */ + +static void test_long_data() +{ + MYSQL_STMT *stmt; + int rc, int_data; + char *data= NullS; + MYSQL_RES *result; + MYSQL_BIND my_bind[3]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_long_data"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_long_data(col1 int, " + " col2 long varchar, col3 long varbinary)"); + myquery(rc); + + strmov(query, "INSERT INTO test_long_data(col1, col2) VALUES(?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt_r(stmt); + + strmov(query, "INSERT INTO test_long_data(col1, col2, col3) VALUES(?, ?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 3); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer= (void *)&int_data; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + + my_bind[2]= my_bind[1]; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + int_data= 999; + data= (char *)"Michael"; + + /* supply data in pieces */ + rc= mysql_stmt_send_long_data(stmt, 1, data, strlen(data)); + data= (char *)" 'Monty' Widenius"; + rc= mysql_stmt_send_long_data(stmt, 1, data, strlen(data)); + check_execute(stmt, rc); + rc= mysql_stmt_send_long_data(stmt, 2, "Venu (venu@mysql.com)", 4); + check_execute(stmt, rc); + + /* execute */ + rc= mysql_stmt_execute(stmt); + if (!opt_silent) + fprintf(stdout, " mysql_stmt_execute() returned %d\n", rc); + check_execute(stmt, rc); + + rc= mysql_commit(mysql); + myquery(rc); + + /* now fetch the results ..*/ + rc= mysql_query(mysql, "SELECT * FROM test_long_data"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); + + verify_col_data("test_long_data", "col1", "999"); + verify_col_data("test_long_data", "col2", "Michael 'Monty' Widenius"); + verify_col_data("test_long_data", "col3", "Venu"); + mysql_stmt_close(stmt); +} + + +/* Test long data (string) handling */ + +static void test_long_data_str() +{ + MYSQL_STMT *stmt; + int rc, i; + char data[255]; + long length; + ulong length1; + MYSQL_RES *result; + MYSQL_BIND my_bind[2]; + my_bool is_null[2]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_long_data_str"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data_str"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_long_data_str(id int, longstr long varchar)"); + myquery(rc); + + strmov(query, "INSERT INTO test_long_data_str VALUES(?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer= (void *)&length; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].is_null= &is_null[0]; + is_null[0]= 0; + length= 0; + + my_bind[1].buffer= data; /* string data */ + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].length= &length1; + my_bind[1].is_null= &is_null[1]; + is_null[1]= 0; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + length= 40; + strmov(data, "MySQL AB"); + + /* supply data in pieces */ + for(i= 0; i < 4; i++) + { + rc= mysql_stmt_send_long_data(stmt, 1, (char *)data, 5); + check_execute(stmt, rc); + } + /* execute */ + rc= mysql_stmt_execute(stmt); + if (!opt_silent) + fprintf(stdout, " mysql_stmt_execute() returned %d\n", rc); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_commit(mysql); + myquery(rc); + + /* now fetch the results ..*/ + rc= mysql_query(mysql, "SELECT LENGTH(longstr), longstr FROM test_long_data_str"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); + + sprintf(data, "%d", i*5); + verify_col_data("test_long_data_str", "LENGTH(longstr)", data); + data[0]= '\0'; + while (i--) + strxmov(data, data, "MySQL", NullS); + verify_col_data("test_long_data_str", "longstr", data); + + rc= mysql_query(mysql, "DROP TABLE test_long_data_str"); + myquery(rc); +} + + +/* Test long data (string) handling */ + +static void test_long_data_str1() +{ + MYSQL_STMT *stmt; + int rc, i; + char data[255]; + long length; + ulong max_blob_length, blob_length= 0, length1; + my_bool true_value; + MYSQL_RES *result; + MYSQL_BIND my_bind[2]; + MYSQL_FIELD *field; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_long_data_str1"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data_str"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_long_data_str(longstr long varchar, blb long varbinary)"); + myquery(rc); + + strmov(query, "INSERT INTO test_long_data_str VALUES(?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer= data; /* string data */ + my_bind[0].buffer_length= sizeof(data); + my_bind[0].length= &length1; + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + length1= 0; + + my_bind[1]= my_bind[0]; + my_bind[1].buffer_type= MYSQL_TYPE_BLOB; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + length= sprintf(data, "MySQL AB"); + + /* supply data in pieces */ + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_send_long_data(stmt, 0, data, length); + check_execute(stmt, rc); + + rc= mysql_stmt_send_long_data(stmt, 1, data, 2); + check_execute(stmt, rc); + } + + /* execute */ + rc= mysql_stmt_execute(stmt); + if (!opt_silent) + fprintf(stdout, " mysql_stmt_execute() returned %d\n", rc); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_commit(mysql); + myquery(rc); + + /* now fetch the results ..*/ + rc= mysql_query(mysql, "SELECT LENGTH(longstr), longstr, LENGTH(blb), blb FROM test_long_data_str"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + + mysql_field_seek(result, 1); + field= mysql_fetch_field(result); + max_blob_length= field->max_length; + + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); + + sprintf(data, "%ld", (long)i*length); + verify_col_data("test_long_data_str", "length(longstr)", data); + + sprintf(data, "%d", i*2); + verify_col_data("test_long_data_str", "length(blb)", data); + + /* Test length of field->max_length */ + stmt= mysql_simple_prepare(mysql, "SELECT * from test_long_data_str"); + check_stmt(stmt); + verify_param_count(stmt, 0); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + result= mysql_stmt_result_metadata(stmt); + field= mysql_fetch_fields(result); + + /* First test what happens if STMT_ATTR_UPDATE_MAX_LENGTH is not used */ + DIE_UNLESS(field->max_length == 0); + mysql_free_result(result); + + /* Enable updating of field->max_length */ + true_value= 1; + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &true_value); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + result= mysql_stmt_result_metadata(stmt); + field= mysql_fetch_fields(result); + + DIE_UNLESS(field->max_length == max_blob_length); + + /* Fetch results into a data buffer that is smaller than data */ + bzero((char*) my_bind, sizeof(*my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_BLOB; + my_bind[0].buffer= (void *) &data; /* this buffer won't be altered */ + my_bind[0].buffer_length= 16; + my_bind[0].length= &blob_length; + my_bind[0].error= &my_bind[0].error_value; + rc= mysql_stmt_bind_result(stmt, my_bind); + data[16]= 0; + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED); + DIE_UNLESS(my_bind[0].error_value); + DIE_UNLESS(strlen(data) == 16); + DIE_UNLESS(blob_length == max_blob_length); + + /* Fetch all data */ + bzero((char*) (my_bind+1), sizeof(*my_bind)); + my_bind[1].buffer_type= MYSQL_TYPE_BLOB; + my_bind[1].buffer= (void *) &data; /* this buffer won't be altered */ + my_bind[1].buffer_length= sizeof(data); + my_bind[1].length= &blob_length; + bzero(data, sizeof(data)); + mysql_stmt_fetch_column(stmt, my_bind+1, 0, 0); + DIE_UNLESS(strlen(data) == max_blob_length); + + mysql_free_result(result); + mysql_stmt_close(stmt); + + /* Drop created table */ + rc= mysql_query(mysql, "DROP TABLE test_long_data_str"); + myquery(rc); +} + + +/* Test long data (binary) handling */ + +static void test_long_data_bin() +{ + MYSQL_STMT *stmt; + int rc; + char data[255]; + long length; + MYSQL_RES *result; + MYSQL_BIND my_bind[2]; + char query[MAX_TEST_QUERY_LENGTH]; + + + myheader("test_long_data_bin"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data_bin"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_long_data_bin(id int, longbin long varbinary)"); + myquery(rc); + + strmov(query, "INSERT INTO test_long_data_bin VALUES(?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer= (void *)&length; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + length= 0; + + my_bind[1].buffer= data; /* string data */ + my_bind[1].buffer_type= MYSQL_TYPE_LONG_BLOB; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + length= 10; + strmov(data, "MySQL AB"); + + /* supply data in pieces */ + { + int i; + for (i= 0; i < 100; i++) + { + rc= mysql_stmt_send_long_data(stmt, 1, (char *)data, 4); + check_execute(stmt, rc); + } + } + /* execute */ + rc= mysql_stmt_execute(stmt); + if (!opt_silent) + fprintf(stdout, " mysql_stmt_execute() returned %d\n", rc); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_commit(mysql); + myquery(rc); + + /* now fetch the results ..*/ + rc= mysql_query(mysql, "SELECT LENGTH(longbin), longbin FROM test_long_data_bin"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); +} + + +/* Test simple delete */ + +static void test_simple_delete() +{ + MYSQL_STMT *stmt; + int rc; + char szData[30]= {0}; + int nData= 1; + MYSQL_RES *result; + MYSQL_BIND my_bind[2]; + ulong length[2]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_simple_delete"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_simple_delete"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_simple_delete(col1 int, \ + col2 varchar(50), col3 int )"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_simple_delete VALUES(1, 'MySQL', 100)"); + myquery(rc); + + verify_affected_rows(1); + + rc= mysql_commit(mysql); + myquery(rc); + + /* insert by prepare */ + strmov(query, "DELETE FROM test_simple_delete WHERE col1= ? AND " + "CONVERT(col2 USING utf8)= ? AND col3= 100"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + nData= 1; + strmov(szData, "MySQL"); + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= szData; /* string data */ + my_bind[1].buffer_length= sizeof(szData); + my_bind[1].length= &length[1]; + length[1]= 5; + + my_bind[0].buffer= (void *)&nData; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_affected_rows(1); + + mysql_stmt_close(stmt); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); + + /* test the results now, only one row should exist */ + rc= mysql_query(mysql, "SELECT * FROM test_simple_delete"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 0); + mysql_free_result(result); +} + + +/* Test simple update */ + +static void test_update() +{ + MYSQL_STMT *stmt; + int rc; + char szData[25]; + int nData= 1; + MYSQL_RES *result; + MYSQL_BIND my_bind[2]; + ulong length[2]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_update"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_update"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_update(" + "col1 int primary key auto_increment, " + "col2 varchar(50), col3 int )"); + myquery(rc); + + strmov(query, "INSERT INTO test_update(col2, col3) VALUES(?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + /* string data */ + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= szData; + my_bind[0].buffer_length= sizeof(szData); + my_bind[0].length= &length[0]; + length[0]= sprintf(szData, "inserted-data"); + + my_bind[1].buffer= (void *)&nData; + my_bind[1].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + nData= 100; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_affected_rows(1); + mysql_stmt_close(stmt); + + strmov(query, "UPDATE test_update SET col2= ? WHERE col3= ?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + nData= 100; + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= szData; + my_bind[0].buffer_length= sizeof(szData); + my_bind[0].length= &length[0]; + length[0]= sprintf(szData, "updated-data"); + + my_bind[1].buffer= (void *)&nData; + my_bind[1].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + verify_affected_rows(1); + + mysql_stmt_close(stmt); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); + + /* test the results now, only one row should exist */ + rc= mysql_query(mysql, "SELECT * FROM test_update"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); +} + + +/* Test prepare without parameters */ + +static void test_prepare_noparam() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_RES *result; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_prepare_noparam"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS my_prepare"); + myquery(rc); + + + rc= mysql_query(mysql, "CREATE TABLE my_prepare(col1 int, col2 varchar(50))"); + myquery(rc); + + /* insert by prepare */ + strmov(query, "INSERT INTO my_prepare VALUES(10, 'venu')"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 0); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); + + /* test the results now, only one row should exist */ + rc= mysql_query(mysql, "SELECT * FROM my_prepare"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); +} + + +/* Test simple bind result */ + +static void test_bind_result() +{ + MYSQL_STMT *stmt; + int rc; + int nData; + ulong length1; + char szData[100]; + MYSQL_BIND my_bind[2]; + my_bool is_null[2]; + + myheader("test_bind_result"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_result(col1 int , col2 varchar(50))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES(10, 'venu')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES(20, 'MySQL')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_bind_result(col2) VALUES('monty')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + /* fetch */ + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *) &nData; /* integer data */ + my_bind[0].is_null= &is_null[0]; + + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= szData; /* string data */ + my_bind[1].buffer_length= sizeof(szData); + my_bind[1].length= &length1; + my_bind[1].is_null= &is_null[1]; + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_bind_result"); + check_stmt(stmt); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 1: %d, %s(%lu)", nData, szData, length1); + DIE_UNLESS(nData == 10); + DIE_UNLESS(strcmp(szData, "venu") == 0); + DIE_UNLESS(length1 == 4); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 2: %d, %s(%lu)", nData, szData, length1); + DIE_UNLESS(nData == 20); + DIE_UNLESS(strcmp(szData, "MySQL") == 0); + DIE_UNLESS(length1 == 5); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent && is_null[0]) + fprintf(stdout, "\n row 3: NULL, %s(%lu)", szData, length1); + DIE_UNLESS(is_null[0]); + DIE_UNLESS(strcmp(szData, "monty") == 0); + DIE_UNLESS(length1 == 5); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Test ext bind result */ + +static void test_bind_result_ext() +{ + MYSQL_STMT *stmt; + int rc, i; + uchar t_data; + short s_data; + int i_data; + longlong b_data; + float f_data; + double d_data; + char szData[20], bData[20]; + ulong szLength, bLength; + MYSQL_BIND my_bind[8]; + ulong length[8]; + my_bool is_null[8]; + char llbuf[22]; + myheader("test_bind_result_ext"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_result(c1 tinyint, " + " c2 smallint, " + " c3 int, c4 bigint, " + " c5 float, c6 double, " + " c7 varbinary(10), " + " c8 varchar(50))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_bind_result " + "VALUES (19, 2999, 3999, 4999999, " + " 2345.6, 5678.89563, 'venu', 'mysql')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + bzero((char*) my_bind, sizeof(my_bind)); + for (i= 0; i < (int) array_elements(my_bind); i++) + { + my_bind[i].length= &length[i]; + my_bind[i].is_null= &is_null[i]; + } + + my_bind[0].buffer_type= MYSQL_TYPE_TINY; + my_bind[0].buffer= (void *)&t_data; + + my_bind[1].buffer_type= MYSQL_TYPE_SHORT; + my_bind[2].buffer_type= MYSQL_TYPE_LONG; + + my_bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + my_bind[1].buffer= (void *)&s_data; + + my_bind[2].buffer= (void *)&i_data; + my_bind[3].buffer= (void *)&b_data; + + my_bind[4].buffer_type= MYSQL_TYPE_FLOAT; + my_bind[4].buffer= (void *)&f_data; + + my_bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + my_bind[5].buffer= (void *)&d_data; + + my_bind[6].buffer_type= MYSQL_TYPE_STRING; + my_bind[6].buffer= (void *)szData; + my_bind[6].buffer_length= sizeof(szData); + my_bind[6].length= &szLength; + + my_bind[7].buffer_type= MYSQL_TYPE_TINY_BLOB; + my_bind[7].buffer= (void *)&bData; + my_bind[7].length= &bLength; + my_bind[7].buffer_length= sizeof(bData); + + stmt= mysql_simple_prepare(mysql, "select * from test_bind_result"); + check_stmt(stmt); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + { + fprintf(stdout, "\n data (tiny) : %d", t_data); + fprintf(stdout, "\n data (short) : %d", s_data); + fprintf(stdout, "\n data (int) : %d", i_data); + fprintf(stdout, "\n data (big) : %s", llstr(b_data, llbuf)); + + fprintf(stdout, "\n data (float) : %f", f_data); + fprintf(stdout, "\n data (double) : %f", d_data); + + fprintf(stdout, "\n data (str) : %s(%lu)", szData, szLength); + + bData[bLength]= '\0'; /* bData is binary */ + fprintf(stdout, "\n data (bin) : %s(%lu)", bData, bLength); + } + + DIE_UNLESS(t_data == 19); + DIE_UNLESS(s_data == 2999); + DIE_UNLESS(i_data == 3999); + DIE_UNLESS(b_data == 4999999); + /*DIE_UNLESS(f_data == 2345.60);*/ + /*DIE_UNLESS(d_data == 5678.89563);*/ + DIE_UNLESS(strcmp(szData, "venu") == 0); + DIE_UNLESS(strncmp(bData, "mysql", 5) == 0); + DIE_UNLESS(szLength == 4); + DIE_UNLESS(bLength == 5); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Test ext bind result */ + +static void test_bind_result_ext1() +{ + MYSQL_STMT *stmt; + uint i; + int rc; + char t_data[20]; + float s_data; + short i_data; + uchar b_data; + int f_data; + long bData; + char d_data[20]; + double szData; + MYSQL_BIND my_bind[8]; + ulong length[8]; + my_bool is_null[8]; + myheader("test_bind_result_ext1"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_result(c1 tinyint, c2 smallint, \ + c3 int, c4 bigint, \ + c5 float, c6 double, \ + c7 varbinary(10), \ + c8 varchar(10))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES(120, 2999, 3999, 54, \ + 2.6, 58.89, \ + '206', '6.7')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *) t_data; + my_bind[0].buffer_length= sizeof(t_data); + my_bind[0].error= &my_bind[0].error_value; + + my_bind[1].buffer_type= MYSQL_TYPE_FLOAT; + my_bind[1].buffer= (void *)&s_data; + my_bind[1].buffer_length= 0; + my_bind[1].error= &my_bind[1].error_value; + + my_bind[2].buffer_type= MYSQL_TYPE_SHORT; + my_bind[2].buffer= (void *)&i_data; + my_bind[2].buffer_length= 0; + my_bind[2].error= &my_bind[2].error_value; + + my_bind[3].buffer_type= MYSQL_TYPE_TINY; + my_bind[3].buffer= (void *)&b_data; + my_bind[3].buffer_length= 0; + my_bind[3].error= &my_bind[3].error_value; + + my_bind[4].buffer_type= MYSQL_TYPE_LONG; + my_bind[4].buffer= (void *)&f_data; + my_bind[4].buffer_length= 0; + my_bind[4].error= &my_bind[4].error_value; + + my_bind[5].buffer_type= MYSQL_TYPE_STRING; + my_bind[5].buffer= (void *)d_data; + my_bind[5].buffer_length= sizeof(d_data); + my_bind[5].error= &my_bind[5].error_value; + + my_bind[6].buffer_type= MYSQL_TYPE_LONG; + my_bind[6].buffer= (void *)&bData; + my_bind[6].buffer_length= 0; + my_bind[6].error= &my_bind[6].error_value; + + my_bind[7].buffer_type= MYSQL_TYPE_DOUBLE; + my_bind[7].buffer= (void *)&szData; + my_bind[7].buffer_length= 0; + my_bind[7].error= &my_bind[7].error_value; + + for (i= 0; i < array_elements(my_bind); i++) + { + my_bind[i].is_null= &is_null[i]; + my_bind[i].length= &length[i]; + } + + stmt= mysql_simple_prepare(mysql, "select * from test_bind_result"); + check_stmt(stmt); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + printf("rc=%d\n", rc); + DIE_UNLESS(rc == 0); + + if (!opt_silent) + { + fprintf(stdout, "\n data (tiny) : %s(%lu)", t_data, length[0]); + fprintf(stdout, "\n data (short) : %f(%lu)", s_data, length[1]); + fprintf(stdout, "\n data (int) : %d(%lu)", i_data, length[2]); + fprintf(stdout, "\n data (big) : %d(%lu)", b_data, length[3]); + + fprintf(stdout, "\n data (float) : %d(%lu)", f_data, length[4]); + fprintf(stdout, "\n data (double) : %s(%lu)", d_data, length[5]); + + fprintf(stdout, "\n data (bin) : %ld(%lu)", bData, length[6]); + fprintf(stdout, "\n data (str) : %g(%lu)", szData, length[7]); + } + + DIE_UNLESS(strcmp(t_data, "120") == 0); + DIE_UNLESS(i_data == 3999); + DIE_UNLESS(f_data == 2); + DIE_UNLESS(strcmp(d_data, "58.89") == 0); + DIE_UNLESS(b_data == 54); + + DIE_UNLESS(length[0] == 3); + DIE_UNLESS(length[1] == 4); + DIE_UNLESS(length[2] == 2); + DIE_UNLESS(length[3] == 1); + DIE_UNLESS(length[4] == 4); + DIE_UNLESS(length[5] == 5); + DIE_UNLESS(length[6] == 4); + DIE_UNLESS(length[7] == 8); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Generalized fetch conversion routine for all basic types */ + +static void bind_fetch(int row_count) +{ + MYSQL_STMT *stmt; + int rc, i, count= row_count; + int32 data[10]; + int8 i8_data; + int16 i16_data; + int32 i32_data; + longlong i64_data; + float f_data; + double d_data; + char s_data[10]; + ulong length[10]; + MYSQL_BIND my_bind[7]; + my_bool is_null[7]; + + stmt= mysql_simple_prepare(mysql, "INSERT INTO test_bind_fetch VALUES " + "(?, ?, ?, ?, ?, ?, ?)"); + check_stmt(stmt); + + verify_param_count(stmt, 7); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + for (i= 0; i < (int) array_elements(my_bind); i++) + { + my_bind[i].buffer_type= MYSQL_TYPE_LONG; + my_bind[i].buffer= (void *) &data[i]; + } + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + while (count--) + { + rc= 10+count; + for (i= 0; i < (int) array_elements(my_bind); i++) + { + data[i]= rc+i; + rc+= 12; + } + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + + rc= mysql_commit(mysql); + myquery(rc); + + mysql_stmt_close(stmt); + + rc= my_stmt_result("SELECT * FROM test_bind_fetch"); + DIE_UNLESS(row_count == rc); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_bind_fetch"); + check_stmt(stmt); + + for (i= 0; i < (int) array_elements(my_bind); i++) + { + my_bind[i].buffer= (void *) &data[i]; + my_bind[i].length= &length[i]; + my_bind[i].is_null= &is_null[i]; + } + + my_bind[0].buffer_type= MYSQL_TYPE_TINY; + my_bind[0].buffer= (void *)&i8_data; + + my_bind[1].buffer_type= MYSQL_TYPE_SHORT; + my_bind[1].buffer= (void *)&i16_data; + + my_bind[2].buffer_type= MYSQL_TYPE_LONG; + my_bind[2].buffer= (void *)&i32_data; + + my_bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + my_bind[3].buffer= (void *)&i64_data; + + my_bind[4].buffer_type= MYSQL_TYPE_FLOAT; + my_bind[4].buffer= (void *)&f_data; + + my_bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + my_bind[5].buffer= (void *)&d_data; + + my_bind[6].buffer_type= MYSQL_TYPE_STRING; + my_bind[6].buffer= (void *)&s_data; + my_bind[6].buffer_length= sizeof(s_data); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + while (row_count--) + { + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + { + fprintf(stdout, "\n"); + fprintf(stdout, "\n tiny : %ld(%lu)", (ulong) i8_data, length[0]); + fprintf(stdout, "\n short : %ld(%lu)", (ulong) i16_data, length[1]); + fprintf(stdout, "\n int : %ld(%lu)", (ulong) i32_data, length[2]); + fprintf(stdout, "\n longlong : %ld(%lu)", (ulong) i64_data, length[3]); + fprintf(stdout, "\n float : %f(%lu)", f_data, length[4]); + fprintf(stdout, "\n double : %g(%lu)", d_data, length[5]); + fprintf(stdout, "\n char : %s(%lu)", s_data, length[6]); + } + rc= 10+row_count; + + /* TINY */ + DIE_UNLESS((int) i8_data == rc); + DIE_UNLESS(length[0] == 1); + rc+= 13; + + /* SHORT */ + DIE_UNLESS((int) i16_data == rc); + DIE_UNLESS(length[1] == 2); + rc+= 13; + + /* LONG */ + DIE_UNLESS((int) i32_data == rc); + DIE_UNLESS(length[2] == 4); + rc+= 13; + + /* LONGLONG */ + DIE_UNLESS((int) i64_data == rc); + DIE_UNLESS(length[3] == 8); + rc+= 13; + + /* FLOAT */ + DIE_UNLESS((int)f_data == rc); + DIE_UNLESS(length[4] == 4); + rc+= 13; + + /* DOUBLE */ + DIE_UNLESS((int)d_data == rc); + DIE_UNLESS(length[5] == 8); + rc+= 13; + + /* CHAR */ + { + char buff[20]; + long len= sprintf(buff, "%d", rc); + DIE_UNLESS(strcmp(s_data, buff) == 0); + DIE_UNLESS(length[6] == (ulong) len); + } + } + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Test fetching of date, time and ts */ + +static void test_fetch_date() +{ + MYSQL_STMT *stmt; + uint i; + int rc, year; + char date[25], my_time[25], ts[25], ts_4[25], ts_6[20], dt[20]; + ulong d_length, t_length, ts_length, ts4_length, ts6_length, + dt_length, y_length; + MYSQL_BIND my_bind[8]; + my_bool is_null[8]; + ulong length[8]; + + myheader("test_fetch_date"); + + /* Will not work if sql_mode is NO_ZERO_DATE (implicit if TRADITIONAL) */ + rc= mysql_query(mysql, "SET SQL_MODE=''"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_result(c1 date, c2 time, \ + c3 timestamp, \ + c4 year, \ + c5 datetime, \ + c6 timestamp, \ + c7 timestamp)"); + myquery(rc); + + rc= mysql_query(mysql, "SET SQL_MODE=''"); + rc= mysql_query(mysql, "INSERT INTO test_bind_result VALUES('2002-01-02', \ + '12:49:00', \ + '2002-01-02 17:46:59', \ + 2010, \ + '2010-07-10', \ + '2020', '1999-12-29')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + bzero((char*) my_bind, sizeof(my_bind)); + for (i= 0; i < array_elements(my_bind); i++) + { + my_bind[i].is_null= &is_null[i]; + my_bind[i].length= &length[i]; + } + + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[1]= my_bind[2]= my_bind[0]; + + my_bind[0].buffer= (void *)&date; + my_bind[0].buffer_length= sizeof(date); + my_bind[0].length= &d_length; + + my_bind[1].buffer= (void *)&my_time; + my_bind[1].buffer_length= sizeof(my_time); + my_bind[1].length= &t_length; + + my_bind[2].buffer= (void *)&ts; + my_bind[2].buffer_length= sizeof(ts); + my_bind[2].length= &ts_length; + + my_bind[3].buffer_type= MYSQL_TYPE_LONG; + my_bind[3].buffer= (void *)&year; + my_bind[3].length= &y_length; + + my_bind[4].buffer_type= MYSQL_TYPE_STRING; + my_bind[4].buffer= (void *)&dt; + my_bind[4].buffer_length= sizeof(dt); + my_bind[4].length= &dt_length; + + my_bind[5].buffer_type= MYSQL_TYPE_STRING; + my_bind[5].buffer= (void *)&ts_4; + my_bind[5].buffer_length= sizeof(ts_4); + my_bind[5].length= &ts4_length; + + my_bind[6].buffer_type= MYSQL_TYPE_STRING; + my_bind[6].buffer= (void *)&ts_6; + my_bind[6].buffer_length= sizeof(ts_6); + my_bind[6].length= &ts6_length; + + rc= my_stmt_result("SELECT * FROM test_bind_result"); + DIE_UNLESS(rc == 1); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_bind_result"); + check_stmt(stmt); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + ts_4[0]= '\0'; + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + { + fprintf(stdout, "\n date : %s(%lu)", date, d_length); + fprintf(stdout, "\n time : %s(%lu)", my_time, t_length); + fprintf(stdout, "\n ts : %s(%lu)", ts, ts_length); + fprintf(stdout, "\n year : %d(%lu)", year, y_length); + fprintf(stdout, "\n dt : %s(%lu)", dt, dt_length); + fprintf(stdout, "\n ts(4) : %s(%lu)", ts_4, ts4_length); + fprintf(stdout, "\n ts(6) : %s(%lu)", ts_6, ts6_length); + } + + DIE_UNLESS(strcmp(date, "2002-01-02") == 0); + DIE_UNLESS(d_length == 10); + + DIE_UNLESS(strcmp(my_time, "12:49:00") == 0); + DIE_UNLESS(t_length == 8); + + DIE_UNLESS(strcmp(ts, "2002-01-02 17:46:59") == 0); + DIE_UNLESS(ts_length == 19); + + DIE_UNLESS(year == 2010); + DIE_UNLESS(y_length == 4); + + DIE_UNLESS(strcmp(dt, "2010-07-10 00:00:00") == 0); + DIE_UNLESS(dt_length == 19); + + DIE_UNLESS(strcmp(ts_4, "0000-00-00 00:00:00") == 0); + DIE_UNLESS(ts4_length == strlen("0000-00-00 00:00:00")); + + DIE_UNLESS(strcmp(ts_6, "1999-12-29 00:00:00") == 0); + DIE_UNLESS(ts6_length == 19); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Test fetching of str to all types */ + +static void test_fetch_str() +{ + int rc; + + myheader("test_fetch_str"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 char(10), \ + c2 char(10), \ + c3 char(20), \ + c4 char(20), \ + c5 char(30), \ + c6 char(40), \ + c7 char(20))"); + myquery(rc); + + bind_fetch(3); +} + + +/* Test fetching of long to all types */ + +static void test_fetch_long() +{ + int rc; + + myheader("test_fetch_long"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 int unsigned, \ + c2 int unsigned, \ + c3 int, \ + c4 int, \ + c5 int, \ + c6 int unsigned, \ + c7 int)"); + myquery(rc); + + bind_fetch(4); +} + + +/* Test fetching of short to all types */ + +static void test_fetch_short() +{ + int rc; + + myheader("test_fetch_short"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 smallint unsigned, \ + c2 smallint, \ + c3 smallint unsigned, \ + c4 smallint, \ + c5 smallint, \ + c6 smallint, \ + c7 smallint unsigned)"); + myquery(rc); + + bind_fetch(5); +} + + +/* Test fetching of tiny to all types */ + +static void test_fetch_tiny() +{ + int rc; + + myheader("test_fetch_tiny"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 tinyint unsigned, \ + c2 tinyint, \ + c3 tinyint unsigned, \ + c4 tinyint, \ + c5 tinyint, \ + c6 tinyint, \ + c7 tinyint unsigned)"); + myquery(rc); + + bind_fetch(3); + +} + + +/* Test fetching of longlong to all types */ + +static void test_fetch_bigint() +{ + int rc; + + myheader("test_fetch_bigint"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 bigint, \ + c2 bigint, \ + c3 bigint unsigned, \ + c4 bigint unsigned, \ + c5 bigint unsigned, \ + c6 bigint unsigned, \ + c7 bigint unsigned)"); + myquery(rc); + + bind_fetch(2); + +} + + +/* Test fetching of float to all types */ + +static void test_fetch_float() +{ + int rc; + + myheader("test_fetch_float"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 float(3), \ + c2 float, \ + c3 float unsigned, \ + c4 float, \ + c5 float, \ + c6 float, \ + c7 float(10) unsigned)"); + myquery(rc); + + bind_fetch(2); + +} + + +/* Test fetching of double to all types */ + +static void test_fetch_double() +{ + int rc; + + myheader("test_fetch_double"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_fetch"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bind_fetch(c1 double(5, 2), " + "c2 double unsigned, c3 double unsigned, " + "c4 double unsigned, c5 double unsigned, " + "c6 double unsigned, c7 double unsigned)"); + myquery(rc); + + bind_fetch(3); + +} + + +/* Test simple prepare with all possible types */ + +static void test_prepare_ext() +{ + MYSQL_STMT *stmt; + int rc; + char *sql; + int nData= 1; + char tData= 1; + short sData= 10; + longlong bData= 20; + MYSQL_BIND my_bind[6]; + char query[MAX_TEST_QUERY_LENGTH]; + myheader("test_prepare_ext"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_ext"); + myquery(rc); + + sql= (char *)"CREATE TABLE test_prepare_ext" + "(" + " c1 tinyint," + " c2 smallint," + " c3 mediumint," + " c4 int," + " c5 integer," + " c6 bigint," + " c7 float," + " c8 double," + " c9 double precision," + " c10 real," + " c11 decimal(7, 4)," + " c12 numeric(8, 4)," + " c13 date," + " c14 datetime," + " c15 timestamp," + " c16 time," + " c17 year," + " c18 bit," + " c19 bool," + " c20 char," + " c21 char(10)," + " c22 varchar(30)," + " c23 tinyblob," + " c24 tinytext," + " c25 blob," + " c26 text," + " c27 mediumblob," + " c28 mediumtext," + " c29 longblob," + " c30 longtext," + " c31 enum('one', 'two', 'three')," + " c32 set('monday', 'tuesday', 'wednesday'))"; + + rc= mysql_query(mysql, sql); + myquery(rc); + + /* insert by prepare - all integers */ + strmov(query, (char *)"INSERT INTO test_prepare_ext(c1, c2, c3, c4, c5, c6) VALUES(?, ?, ?, ?, ?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 6); + + /* Always bzero all members of bind parameter */ + bzero((char*) my_bind, sizeof(my_bind)); + + /*tinyint*/ + my_bind[0].buffer_type= MYSQL_TYPE_TINY; + my_bind[0].buffer= (void *)&tData; + + /*smallint*/ + my_bind[1].buffer_type= MYSQL_TYPE_SHORT; + my_bind[1].buffer= (void *)&sData; + + /*mediumint*/ + my_bind[2].buffer_type= MYSQL_TYPE_LONG; + my_bind[2].buffer= (void *)&nData; + + /*int*/ + my_bind[3].buffer_type= MYSQL_TYPE_LONG; + my_bind[3].buffer= (void *)&nData; + + /*integer*/ + my_bind[4].buffer_type= MYSQL_TYPE_LONG; + my_bind[4].buffer= (void *)&nData; + + /*bigint*/ + my_bind[5].buffer_type= MYSQL_TYPE_LONGLONG; + my_bind[5].buffer= (void *)&bData; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + /* + * integer to integer + */ + for (nData= 0; nData<10; nData++, tData++, sData++, bData++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + mysql_stmt_close(stmt); + + /* now fetch the results ..*/ + + stmt= mysql_simple_prepare(mysql, "SELECT c1, c2, c3, c4, c5, c6 " + "FROM test_prepare_ext"); + check_stmt(stmt); + + /* get the result */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(nData == rc); + + mysql_stmt_close(stmt); +} + + +/* Test real and alias names */ + +static void test_field_names() +{ + int rc; + MYSQL_RES *result; + + myheader("test_field_names"); + + if (!opt_silent) + fprintf(stdout, "\n %d, %d, %d", MYSQL_TYPE_DECIMAL, MYSQL_TYPE_NEWDATE, MYSQL_TYPE_ENUM); + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_field_names1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_field_names2"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_field_names1(id int, name varchar(50))"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_field_names2(id int, name varchar(50))"); + myquery(rc); + + /* with table name included with TRUE column name */ + rc= mysql_query(mysql, "SELECT id as 'id-alias' FROM test_field_names1"); + myquery(rc); + + result= mysql_use_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 0); + mysql_free_result(result); + + /* with table name included with TRUE column name */ + rc= mysql_query(mysql, "SELECT t1.id as 'id-alias', test_field_names2.name FROM test_field_names1 t1, test_field_names2"); + myquery(rc); + + result= mysql_use_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 0); + mysql_free_result(result); +} + + +/* Test warnings */ + +static void test_warnings() +{ + int rc; + MYSQL_RES *result; + + myheader("test_warnings"); + + mysql_query(mysql, "DROP TABLE if exists test_non_exists"); + + rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists"); + myquery(rc); + + if (!opt_silent) + fprintf(stdout, "\n total warnings: %d", mysql_warning_count(mysql)); + rc= mysql_query(mysql, "SHOW WARNINGS"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); +} + + +/* Test errors */ + +static void test_errors() +{ + int rc; + MYSQL_RES *result; + + myheader("test_errors"); + + mysql_query(mysql, "DROP TABLE if exists test_non_exists"); + + rc= mysql_query(mysql, "DROP TABLE test_non_exists"); + myquery_r(rc); + + rc= mysql_query(mysql, "SHOW ERRORS"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + (void) my_process_result_set(result); + mysql_free_result(result); +} + + +/* Test simple prepare-insert */ + +static void test_insert() +{ + MYSQL_STMT *stmt; + int rc; + char str_data[50]; + char tiny_data; + MYSQL_RES *result; + MYSQL_BIND my_bind[2]; + ulong length; + + myheader("test_insert"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_insert"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_prep_insert(col1 tinyint, \ + col2 varchar(50))"); + myquery(rc); + + /* insert by prepare */ + stmt= mysql_simple_prepare(mysql, + "INSERT INTO test_prep_insert VALUES(?, ?)"); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + /* tinyint */ + my_bind[0].buffer_type= MYSQL_TYPE_TINY; + my_bind[0].buffer= (void *)&tiny_data; + + /* string */ + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= str_data; + my_bind[1].buffer_length= sizeof(str_data);; + my_bind[1].length= &length; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + /* now, execute the prepared statement to insert 10 records.. */ + for (tiny_data= 0; tiny_data < 3; tiny_data++) + { + length= sprintf(str_data, "MySQL%d", tiny_data); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + + mysql_stmt_close(stmt); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); + + /* test the results now, only one row should exist */ + rc= mysql_query(mysql, "SELECT * FROM test_prep_insert"); + myquery(rc); + + /* get the result */ + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS((int) tiny_data == rc); + mysql_free_result(result); + +} + + +/* Test simple prepare-resultset info */ + +static void test_prepare_resultset() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_RES *result; + + myheader("test_prepare_resultset"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_resultset"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_prepare_resultset(id int, \ + name varchar(50), extra double)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_prepare_resultset"); + check_stmt(stmt); + + verify_param_count(stmt, 0); + + result= mysql_stmt_result_metadata(stmt); + mytest(result); + my_print_result_metadata(result); + mysql_free_result(result); + mysql_stmt_close(stmt); +} + + +/* Test field flags (verify .NET provider) */ + +static void test_field_flags() +{ + int rc; + MYSQL_RES *result; + MYSQL_FIELD *field; + unsigned int i; + + + myheader("test_field_flags"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_field_flags"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_field_flags(id int NOT NULL AUTO_INCREMENT PRIMARY KEY, \ + id1 int NOT NULL, \ + id2 int UNIQUE, \ + id3 int, \ + id4 int NOT NULL, \ + id5 int, \ + KEY(id3, id4))"); + myquery(rc); + + /* with table name included with TRUE column name */ + rc= mysql_query(mysql, "SELECT * FROM test_field_flags"); + myquery(rc); + + result= mysql_use_result(mysql); + mytest(result); + + mysql_field_seek(result, 0); + if (!opt_silent) + fputc('\n', stdout); + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + fprintf(stdout, "\n field:%d", i); + if (field->flags & NOT_NULL_FLAG) + fprintf(stdout, "\n NOT_NULL_FLAG"); + if (field->flags & PRI_KEY_FLAG) + fprintf(stdout, "\n PRI_KEY_FLAG"); + if (field->flags & UNIQUE_KEY_FLAG) + fprintf(stdout, "\n UNIQUE_KEY_FLAG"); + if (field->flags & MULTIPLE_KEY_FLAG) + fprintf(stdout, "\n MULTIPLE_KEY_FLAG"); + if (field->flags & AUTO_INCREMENT_FLAG) + fprintf(stdout, "\n AUTO_INCREMENT_FLAG"); + + } + } + mysql_free_result(result); +} + + +/* Test mysql_stmt_close for open stmts */ + +static void test_stmt_close() +{ + MYSQL *lmysql; + MYSQL_STMT *stmt1, *stmt2, *stmt3, *stmt_x; + MYSQL_BIND my_bind[1]; + MYSQL_RES *result; + unsigned int count; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_stmt_close"); + + if (!opt_silent) + fprintf(stdout, "\n Establishing a test connection ..."); + if (!(lmysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + exit(1); + } + if (!(mysql_real_connect(lmysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + exit(1); + } + mysql_options(lmysql, MYSQL_OPT_RECONNECT, &my_true); + if (!opt_silent) + fprintf(stdout, "OK"); + + + /* set AUTOCOMMIT to ON*/ + mysql_autocommit(lmysql, TRUE); + + rc= mysql_query(lmysql, "SET SQL_MODE = ''"); + myquery(rc); + + rc= mysql_query(lmysql, "DROP TABLE IF EXISTS test_stmt_close"); + myquery(rc); + + rc= mysql_query(lmysql, "CREATE TABLE test_stmt_close(id int)"); + myquery(rc); + + strmov(query, "DO \"nothing\""); + stmt1= mysql_simple_prepare(lmysql, query); + check_stmt(stmt1); + + verify_param_count(stmt1, 0); + + strmov(query, "INSERT INTO test_stmt_close(id) VALUES(?)"); + stmt_x= mysql_simple_prepare(mysql, query); + check_stmt(stmt_x); + + verify_param_count(stmt_x, 1); + + strmov(query, "UPDATE test_stmt_close SET id= ? WHERE id= ?"); + stmt3= mysql_simple_prepare(lmysql, query); + check_stmt(stmt3); + + verify_param_count(stmt3, 2); + + strmov(query, "SELECT * FROM test_stmt_close WHERE id= ?"); + stmt2= mysql_simple_prepare(lmysql, query); + check_stmt(stmt2); + + verify_param_count(stmt2, 1); + + rc= mysql_stmt_close(stmt1); + if (!opt_silent) + fprintf(stdout, "\n mysql_close_stmt(1) returned: %d", rc); + DIE_UNLESS(rc == 0); + + /* + Originally we were going to close all statements automatically in + mysql_close(). This proved to not work well - users weren't able to + close statements by hand once mysql_close() had been called. + Now mysql_close() doesn't free any statements, so this test doesn't + serve its original designation any more. + Here we free stmt2 and stmt3 by hand to avoid memory leaks. + */ + mysql_stmt_close(stmt2); + mysql_stmt_close(stmt3); + mysql_close(lmysql); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer= (void *)&count; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + count= 100; + + rc= mysql_stmt_bind_param(stmt_x, my_bind); + check_execute(stmt_x, rc); + + rc= mysql_stmt_execute(stmt_x); + check_execute(stmt_x, rc); + + verify_st_affected_rows(stmt_x, 1); + + rc= mysql_stmt_close(stmt_x); + if (!opt_silent) + fprintf(stdout, "\n mysql_close_stmt(x) returned: %d", rc); + DIE_UNLESS( rc == 0); + + rc= mysql_query(mysql, "SELECT id FROM test_stmt_close"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); +} + + +/* Test simple set variable prepare */ + +static void test_set_variable() +{ + MYSQL_STMT *stmt, *stmt1; + int rc; + int set_count, def_count, get_count; + ulong length; + char var[NAME_LEN+1]; + MYSQL_BIND set_bind[1], get_bind[2]; + + myheader("test_set_variable"); + + mysql_autocommit(mysql, TRUE); + + stmt1= mysql_simple_prepare(mysql, "show variables like 'max_error_count'"); + check_stmt(stmt1); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) get_bind, sizeof(get_bind)); + + get_bind[0].buffer_type= MYSQL_TYPE_STRING; + get_bind[0].buffer= (void *)var; + get_bind[0].length= &length; + get_bind[0].buffer_length= (int)NAME_LEN; + length= NAME_LEN; + + get_bind[1].buffer_type= MYSQL_TYPE_LONG; + get_bind[1].buffer= (void *)&get_count; + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_bind_result(stmt1, get_bind); + check_execute(stmt1, rc); + + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + + if (!opt_silent) + fprintf(stdout, "\n max_error_count(default): %d", get_count); + def_count= get_count; + + DIE_UNLESS(strcmp(var, "max_error_count") == 0); + rc= mysql_stmt_fetch(stmt1); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + stmt= mysql_simple_prepare(mysql, "set max_error_count= ?"); + check_stmt(stmt); + + bzero((char*) set_bind, sizeof(set_bind)); + + set_bind[0].buffer_type= MYSQL_TYPE_LONG; + set_bind[0].buffer= (void *)&set_count; + + rc= mysql_stmt_bind_param(stmt, set_bind); + check_execute(stmt, rc); + + set_count= 31; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_commit(mysql); + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + + if (!opt_silent) + fprintf(stdout, "\n max_error_count : %d", get_count); + DIE_UNLESS(get_count == set_count); + + rc= mysql_stmt_fetch(stmt1); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + /* restore back to default */ + set_count= def_count; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + + if (!opt_silent) + fprintf(stdout, "\n max_error_count(default): %d", get_count); + DIE_UNLESS(get_count == set_count); + + rc= mysql_stmt_fetch(stmt1); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + mysql_stmt_close(stmt1); +} + +/* Test FUNCTION field info / DATE_FORMAT() table_name . */ + +static void test_func_fields() +{ + int rc; + MYSQL_RES *result; + MYSQL_FIELD *field; + + myheader("test_func_fields"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_dateformat"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_dateformat(id int, \ + ts timestamp)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_dateformat(id) values(10)"); + myquery(rc); + + rc= mysql_query(mysql, "SELECT ts FROM test_dateformat"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + field= mysql_fetch_field(result); + mytest(field); + if (!opt_silent) + fprintf(stdout, "\n table name: `%s` (expected: `%s`)", field->table, + "test_dateformat"); + DIE_UNLESS(strcmp(field->table, "test_dateformat") == 0); + + field= mysql_fetch_field(result); + mytest_r(field); /* no more fields */ + + mysql_free_result(result); + + /* DATE_FORMAT */ + rc= mysql_query(mysql, "SELECT DATE_FORMAT(ts, '%Y') AS 'venu' FROM test_dateformat"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + field= mysql_fetch_field(result); + mytest(field); + if (!opt_silent) + fprintf(stdout, "\n table name: `%s` (expected: `%s`)", field->table, ""); + DIE_UNLESS(field->table[0] == '\0'); + + field= mysql_fetch_field(result); + mytest_r(field); /* no more fields */ + + mysql_free_result(result); + + /* FIELD ALIAS TEST */ + rc= mysql_query(mysql, "SELECT DATE_FORMAT(ts, '%Y') AS 'YEAR' FROM test_dateformat"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + field= mysql_fetch_field(result); + mytest(field); + if (!opt_silent) + { + printf("\n field name: `%s` (expected: `%s`)", field->name, "YEAR"); + printf("\n field org name: `%s` (expected: `%s`)", field->org_name, ""); + } + DIE_UNLESS(strcmp(field->name, "YEAR") == 0); + DIE_UNLESS(field->org_name[0] == '\0'); + + field= mysql_fetch_field(result); + mytest_r(field); /* no more fields */ + + mysql_free_result(result); +} + + +/* Multiple stmts .. */ + +static void test_multi_stmt() +{ + + MYSQL_STMT *stmt, *stmt1, *stmt2; + int rc; + uint32 id; + char name[50]; + MYSQL_BIND my_bind[2]; + ulong length[2]; + my_bool is_null[2]; + myheader("test_multi_stmt"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_multi_table"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_multi_table(id int, name char(20))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_multi_table values(10, 'mysql')"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_multi_table " + "WHERE id= ?"); + check_stmt(stmt); + + stmt2= mysql_simple_prepare(mysql, "UPDATE test_multi_table " + "SET name='updated' WHERE id=10"); + check_stmt(stmt2); + + verify_param_count(stmt, 1); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&id; + my_bind[0].is_null= &is_null[0]; + my_bind[0].length= &length[0]; + is_null[0]= 0; + length[0]= 0; + + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void *)name; + my_bind[1].buffer_length= sizeof(name); + my_bind[1].length= &length[1]; + my_bind[1].is_null= &is_null[1]; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + id= 10; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + id= 999; + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + { + fprintf(stdout, "\n int_data: %lu(%lu)", (ulong) id, length[0]); + fprintf(stdout, "\n str_data: %s(%lu)", name, length[1]); + } + DIE_UNLESS(id == 10); + DIE_UNLESS(strcmp(name, "mysql") == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + /* alter the table schema now */ + stmt1= mysql_simple_prepare(mysql, "DELETE FROM test_multi_table " + "WHERE id= ? AND " + "CONVERT(name USING utf8)=?"); + check_stmt(stmt1); + + verify_param_count(stmt1, 2); + + rc= mysql_stmt_bind_param(stmt1, my_bind); + check_execute(stmt1, rc); + + rc= mysql_stmt_execute(stmt2); + check_execute(stmt2, rc); + + verify_st_affected_rows(stmt2, 1); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + { + fprintf(stdout, "\n int_data: %lu(%lu)", (ulong) id, length[0]); + fprintf(stdout, "\n str_data: %s(%lu)", name, length[1]); + } + DIE_UNLESS(id == 10); + DIE_UNLESS(strcmp(name, "updated") == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + verify_st_affected_rows(stmt1, 1); + + mysql_stmt_close(stmt1); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= my_stmt_result("SELECT * FROM test_multi_table"); + DIE_UNLESS(rc == 0); + + mysql_stmt_close(stmt); + mysql_stmt_close(stmt2); + +} + + +/* Test simple sample - manual */ + +static void test_manual_sample() +{ + unsigned int param_count; + MYSQL_STMT *stmt; + short small_data= 1; + int int_data= 2; + int rc; + char str_data[50]= "std_data"; + ulonglong affected_rows; + MYSQL_BIND my_bind[3]; + my_bool is_null; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_manual_sample"); + + /* + Sample which is incorporated directly in the manual under Prepared + statements section (Example from mysql_stmt_execute() + */ + + mysql_autocommit(mysql, 1); + if (mysql_query(mysql, "DROP TABLE IF EXISTS test_table")) + { + fprintf(stderr, "\n drop table failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(1); + } + if (mysql_query(mysql, "CREATE TABLE test_table(col1 int, col2 varchar(50), \ + col3 smallint, \ + col4 timestamp)")) + { + fprintf(stderr, "\n create table failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(1); + } + + /* Prepare a insert query with 3 parameters */ + strmov(query, "INSERT INTO test_table(col1, col2, col3) values(?, ?, ?)"); + if (!(stmt= mysql_simple_prepare(mysql, query))) + { + fprintf(stderr, "\n prepare, insert failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(1); + } + if (!opt_silent) + fprintf(stdout, "\n prepare, insert successful"); + + /* Get the parameter count from the statement */ + param_count= mysql_stmt_param_count(stmt); + + if (!opt_silent) + fprintf(stdout, "\n total parameters in insert: %d", param_count); + if (param_count != 3) /* validate parameter count */ + { + fprintf(stderr, "\n invalid parameter count returned by MySQL"); + exit(1); + } + + /* Bind the data for the parameters */ + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + /* INTEGER PART */ + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&int_data; + + /* STRING PART */ + my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + my_bind[1].buffer= (void *)str_data; + my_bind[1].buffer_length= sizeof(str_data); + + /* SMALLINT PART */ + my_bind[2].buffer_type= MYSQL_TYPE_SHORT; + my_bind[2].buffer= (void *)&small_data; + my_bind[2].is_null= &is_null; + is_null= 0; + + /* Bind the buffers */ + if (mysql_stmt_bind_param(stmt, my_bind)) + { + fprintf(stderr, "\n param bind failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(1); + } + + /* Specify the data */ + int_data= 10; /* integer */ + strmov(str_data, "MySQL"); /* string */ + + /* INSERT SMALLINT data as NULL */ + is_null= 1; + + /* Execute the insert statement - 1*/ + if (mysql_stmt_execute(stmt)) + { + fprintf(stderr, "\n execute 1 failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(1); + } + + /* Get the total rows affected */ + affected_rows= mysql_stmt_affected_rows(stmt); + + if (!opt_silent) + fprintf(stdout, "\n total affected rows: %ld", (ulong) affected_rows); + if (affected_rows != 1) /* validate affected rows */ + { + fprintf(stderr, "\n invalid affected rows by MySQL"); + exit(1); + } + + /* Re-execute the insert, by changing the values */ + int_data= 1000; + strmov(str_data, "The most popular open source database"); + small_data= 1000; /* smallint */ + is_null= 0; /* reset */ + + /* Execute the insert statement - 2*/ + if (mysql_stmt_execute(stmt)) + { + fprintf(stderr, "\n execute 2 failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(1); + } + + /* Get the total rows affected */ + affected_rows= mysql_stmt_affected_rows(stmt); + + if (!opt_silent) + fprintf(stdout, "\n total affected rows: %ld", (ulong) affected_rows); + if (affected_rows != 1) /* validate affected rows */ + { + fprintf(stderr, "\n invalid affected rows by MySQL"); + exit(1); + } + + /* Close the statement */ + if (mysql_stmt_close(stmt)) + { + fprintf(stderr, "\n failed while closing the statement"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(1); + } + rc= my_stmt_result("SELECT * FROM test_table"); + DIE_UNLESS(rc == 2); + + /* DROP THE TABLE */ + if (mysql_query(mysql, "DROP TABLE test_table")) + { + fprintf(stderr, "\n drop table failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(1); + } + if (!opt_silent) + fprintf(stdout, "Success !!!"); +} + + +/* Test alter table scenario in the middle of prepare */ + +static void test_prepare_alter() +{ + MYSQL_STMT *stmt; + int rc, id; + MYSQL_BIND my_bind[1]; + my_bool is_null; + + myheader("test_prepare_alter"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_alter"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_prep_alter(id int, name char(20))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_prep_alter values(10, 'venu'), (20, 'mysql')"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "INSERT INTO test_prep_alter VALUES(?, 'monty')"); + check_stmt(stmt); + + verify_param_count(stmt, 1); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + is_null= 0; + my_bind[0].buffer_type= MYSQL_TYPE_SHORT; + my_bind[0].buffer= (void *)&id; + my_bind[0].is_null= &is_null; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + id= 30; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + if (thread_query("ALTER TABLE test_prep_alter change id id_new varchar(20)")) + exit(1); + + is_null= 1; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_stmt_result("SELECT * FROM test_prep_alter"); + DIE_UNLESS(rc == 4); + + mysql_stmt_close(stmt); +} + + +/* Test the support of multi-statement executions */ + +static void test_multi_statements() +{ + MYSQL *mysql_local; + MYSQL_RES *result; + int rc; + + const char *query= "\ +DROP TABLE IF EXISTS test_multi_tab;\ +CREATE TABLE test_multi_tab(id int, name char(20));\ +INSERT INTO test_multi_tab(id) VALUES(10), (20);\ +INSERT INTO test_multi_tab VALUES(20, 'insert;comma');\ +SELECT * FROM test_multi_tab;\ +UPDATE test_multi_tab SET name='new;name' WHERE id=20;\ +DELETE FROM test_multi_tab WHERE name='new;name';\ +SELECT * FROM test_multi_tab;\ +DELETE FROM test_multi_tab WHERE id=10;\ +SELECT * FROM test_multi_tab;\ +DROP TABLE test_multi_tab;\ +select 1;\ +DROP TABLE IF EXISTS test_multi_tab"; + uint count, exp_value; + uint rows[]= {0, 0, 2, 1, 3, 2, 2, 1, 1, 0, 0, 1, 0}; + + myheader("test_multi_statements"); + + /* + First test that we get an error for multi statements + (Because default connection is not opened with CLIENT_MULTI_STATEMENTS) + */ + rc= mysql_query(mysql, query); /* syntax error */ + myquery_r(rc); + + rc= mysql_next_result(mysql); + DIE_UNLESS(rc == -1); + rc= mysql_more_results(mysql); + DIE_UNLESS(rc == 0); + + if (!(mysql_local= mysql_client_init(NULL))) + { + fprintf(stdout, "\n mysql_client_init() failed"); + exit(1); + } + + /* Create connection that supports multi statements */ + if (!(mysql_real_connect(mysql_local, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_STATEMENTS))) + { + fprintf(stdout, "\n connection failed(%s)", mysql_error(mysql_local)); + exit(1); + } + mysql_options(mysql_local, MYSQL_OPT_RECONNECT, &my_true); + + rc= mysql_query(mysql_local, query); + myquery(rc); + + for (count= 0 ; count < array_elements(rows) ; count++) + { + if (!opt_silent) + fprintf(stdout, "\n Query %d: ", count); + if ((result= mysql_store_result(mysql_local))) + { + (void) my_process_result_set(result); + mysql_free_result(result); + } + else if (!opt_silent) + fprintf(stdout, "OK, %ld row(s) affected, %ld warning(s)\n", + (ulong) mysql_affected_rows(mysql_local), + (ulong) mysql_warning_count(mysql_local)); + + exp_value= (uint) mysql_affected_rows(mysql_local); + if (rows[count] != exp_value) + { + fprintf(stderr, "row %d had affected rows: %d, should be %d\n", + count, exp_value, rows[count]); + exit(1); + } + if (count != array_elements(rows) -1) + { + if (!(rc= mysql_more_results(mysql_local))) + { + fprintf(stdout, + "mysql_more_result returned wrong value: %d for row %d\n", + rc, count); + exit(1); + } + if ((rc= mysql_next_result(mysql_local))) + { + exp_value= mysql_errno(mysql_local); + + exit(1); + } + } + else + { + rc= mysql_more_results(mysql_local); + DIE_UNLESS(rc == 0); + rc= mysql_next_result(mysql_local); + DIE_UNLESS(rc == -1); + } + } + + /* check that errors abort multi statements */ + + rc= mysql_query(mysql_local, "select 1+1+a;select 1+1"); + myquery_r(rc); + rc= mysql_more_results(mysql_local); + DIE_UNLESS(rc == 0); + rc= mysql_next_result(mysql_local); + DIE_UNLESS(rc == -1); + + rc= mysql_query(mysql_local, "select 1+1;select 1+1+a;select 1"); + myquery(rc); + result= mysql_store_result(mysql_local); + mytest(result); + mysql_free_result(result); + rc= mysql_more_results(mysql_local); + DIE_UNLESS(rc == 1); + rc= mysql_next_result(mysql_local); + DIE_UNLESS(rc > 0); + + /* + Ensure that we can now do a simple query (this checks that the server is + not trying to send us the results for the last 'select 1' + */ + rc= mysql_query(mysql_local, "select 1+1+1"); + myquery(rc); + result= mysql_store_result(mysql_local); + mytest(result); + (void) my_process_result_set(result); + mysql_free_result(result); + + /* + Check if errors in one of the queries handled properly. + */ + rc= mysql_query(mysql_local, "select 1; select * from not_existing_table"); + myquery(rc); + result= mysql_store_result(mysql_local); + mysql_free_result(result); + + rc= mysql_next_result(mysql_local); + DIE_UNLESS(rc > 0); + + rc= mysql_next_result(mysql_local); + DIE_UNLESS(rc < 0); + + mysql_close(mysql_local); +} + + +/* + Check that Prepared statement cannot contain several + SQL statements +*/ + +static void test_prepare_multi_statements() +{ + MYSQL *mysql_local; + MYSQL_STMT *stmt; + char query[MAX_TEST_QUERY_LENGTH]; + myheader("test_prepare_multi_statements"); + + if (!(mysql_local= mysql_client_init(NULL))) + { + fprintf(stderr, "\n mysql_client_init() failed"); + exit(1); + } + + if (!(mysql_real_connect(mysql_local, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_STATEMENTS))) + { + fprintf(stderr, "\n connection failed(%s)", mysql_error(mysql_local)); + exit(1); + } + mysql_options(mysql_local, MYSQL_OPT_RECONNECT, &my_true); + strmov(query, "select 1; select 'another value'"); + stmt= mysql_simple_prepare(mysql_local, query); + check_stmt_r(stmt); + mysql_close(mysql_local); +} + + +/* Test simple bind store result */ + +static void test_store_result() +{ + MYSQL_STMT *stmt; + int rc; + int32 nData; + char szData[100]; + MYSQL_BIND my_bind[2]; + ulong length, length1; + my_bool is_null[2]; + + myheader("test_store_result"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_store_result"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_store_result(col1 int , col2 varchar(50))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_store_result VALUES(10, 'venu'), (20, 'mysql')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_store_result(col2) VALUES('monty')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + /* fetch */ + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *) &nData; /* integer data */ + my_bind[0].length= &length; + my_bind[0].is_null= &is_null[0]; + + length= 0; + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= szData; /* string data */ + my_bind[1].buffer_length= sizeof(szData); + my_bind[1].length= &length1; + my_bind[1].is_null= &is_null[1]; + length1= 0; + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_store_result"); + check_stmt(stmt); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 1: %ld, %s(%lu)", (long) nData, szData, length1); + DIE_UNLESS(nData == 10); + DIE_UNLESS(strcmp(szData, "venu") == 0); + DIE_UNLESS(length1 == 4); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 2: %ld, %s(%lu)", (long) nData, szData, length1); + DIE_UNLESS(nData == 20); + DIE_UNLESS(strcmp(szData, "mysql") == 0); + DIE_UNLESS(length1 == 5); + + length= 99; + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent && is_null[0]) + fprintf(stdout, "\n row 3: NULL, %s(%lu)", szData, length1); + DIE_UNLESS(is_null[0]); + DIE_UNLESS(strcmp(szData, "monty") == 0); + DIE_UNLESS(length1 == 5); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 1: %ld, %s(%lu)", (long) nData, szData, length1); + DIE_UNLESS(nData == 10); + DIE_UNLESS(strcmp(szData, "venu") == 0); + DIE_UNLESS(length1 == 4); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 2: %ld, %s(%lu)", (long) nData, szData, length1); + DIE_UNLESS(nData == 20); + DIE_UNLESS(strcmp(szData, "mysql") == 0); + DIE_UNLESS(length1 == 5); + + length= 99; + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent && is_null[0]) + fprintf(stdout, "\n row 3: NULL, %s(%lu)", szData, length1); + DIE_UNLESS(is_null[0]); + DIE_UNLESS(strcmp(szData, "monty") == 0); + DIE_UNLESS(length1 == 5); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Test simple bind store result */ + +static void test_store_result1() +{ + MYSQL_STMT *stmt; + int rc; + + myheader("test_store_result1"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_store_result"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_store_result(col1 int , col2 varchar(50))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_store_result VALUES(10, 'venu'), (20, 'mysql')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_store_result(col2) VALUES('monty')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_store_result"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= 0; + while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + rc++; + if (!opt_silent) + fprintf(stdout, "\n total rows: %d", rc); + DIE_UNLESS(rc == 3); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= 0; + while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + rc++; + if (!opt_silent) + fprintf(stdout, "\n total rows: %d", rc); + DIE_UNLESS(rc == 3); + + mysql_stmt_close(stmt); +} + + +/* Another test for bind and store result */ + +static void test_store_result2() +{ + MYSQL_STMT *stmt; + int rc; + int nData; + ulong length; + MYSQL_BIND my_bind[1]; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_store_result2"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_store_result"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_store_result(col1 int , col2 varchar(50))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_store_result VALUES(10, 'venu'), (20, 'mysql')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_store_result(col2) VALUES('monty')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *) &nData; /* integer data */ + my_bind[0].length= &length; + my_bind[0].is_null= 0; + + strmov((char *)query , "SELECT col1 FROM test_store_result where col1= ?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + nData= 10; length= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + nData= 0; + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 1: %d", nData); + DIE_UNLESS(nData == 10); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + nData= 20; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + nData= 0; + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 1: %d", nData); + DIE_UNLESS(nData == 20); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + mysql_stmt_close(stmt); +} + + +/* Test simple subselect prepare */ + +static void test_subselect() +{ + + MYSQL_STMT *stmt; + int rc, id; + MYSQL_BIND my_bind[1]; + DBUG_ENTER("test_subselect"); + + myheader("test_subselect"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_sub1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_sub2"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_sub1(id int)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_sub2(id int, id1 int)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_sub1 values(2)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_sub2 VALUES(1, 7), (2, 7)"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + /* fetch */ + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *) &id; + my_bind[0].length= 0; + my_bind[0].is_null= 0; + + stmt= mysql_simple_prepare(mysql, "INSERT INTO test_sub2(id) SELECT * FROM test_sub1 WHERE id= ?"); + check_stmt(stmt); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + id= 2; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_st_affected_rows(stmt, 1); + + id= 9; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_st_affected_rows(stmt, 0); + + mysql_stmt_close(stmt); + + rc= my_stmt_result("SELECT * FROM test_sub2"); + DIE_UNLESS(rc == 3); + + rc= my_stmt_result("SELECT ROW(1, 7) IN (select id, id1 " + "from test_sub2 WHERE id1= 8)"); + DIE_UNLESS(rc == 1); + rc= my_stmt_result("SELECT ROW(1, 7) IN (select id, id1 " + "from test_sub2 WHERE id1= 7)"); + DIE_UNLESS(rc == 1); + + stmt= mysql_simple_prepare(mysql, ("SELECT ROW(1, 7) IN (select id, id1 " + "from test_sub2 WHERE id1= ?)")); + check_stmt(stmt); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + id= 7; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 1: %d", id); + DIE_UNLESS(id == 1); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + id= 8; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 1: %d", id); + DIE_UNLESS(id == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + DBUG_VOID_RETURN; +} + + +/* + Generalized conversion routine to handle DATE, TIME and DATETIME + conversion using MYSQL_TIME structure +*/ + +static void test_bind_date_conv(uint row_count) +{ + MYSQL_STMT *stmt= 0; + uint rc, i, count= row_count; + ulong length[4]; + MYSQL_BIND my_bind[4]; + my_bool is_null[4]= {0}; + MYSQL_TIME tm[4]; + ulong second_part; + uint year, month, day, hour, minute, sec; + uint now_year= 1990, now_month= 3, now_day= 13; + + rc= mysql_query(mysql, "SET timestamp=UNIX_TIMESTAMP('1990-03-13')"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "INSERT INTO test_date VALUES(?, ?, ?, ?)"); + check_stmt(stmt); + + verify_param_count(stmt, 4); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_TIMESTAMP; + my_bind[1].buffer_type= MYSQL_TYPE_TIME; + my_bind[2].buffer_type= MYSQL_TYPE_DATETIME; + my_bind[3].buffer_type= MYSQL_TYPE_DATE; + + for (i= 0; i < (int) array_elements(my_bind); i++) + { + my_bind[i].buffer= (void *) &tm[i]; + my_bind[i].is_null= &is_null[i]; + my_bind[i].length= &length[i]; + my_bind[i].buffer_length= 30; + length[i]= 20; + } + + second_part= 0; + + year= 2000; + month= 01; + day= 10; + + hour= 11; + minute= 16; + sec= 20; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + for (count= 0; count < row_count; count++) + { + for (i= 0; i < (int) array_elements(my_bind); i++) + { + tm[i].neg= 0; + tm[i].second_part= second_part+count; + if (my_bind[i].buffer_type != MYSQL_TYPE_TIME) + { + tm[i].year= year+count; + tm[i].month= month+count; + tm[i].day= day+count; + } + else + tm[i].year= tm[i].month= tm[i].day= 0; + if (my_bind[i].buffer_type != MYSQL_TYPE_DATE) + { + tm[i].hour= hour+count; + tm[i].minute= minute+count; + tm[i].second= sec+count; + } + else + tm[i].hour= tm[i].minute= tm[i].second= 0; + } + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + + rc= mysql_commit(mysql); + myquery(rc); + + mysql_stmt_close(stmt); + + rc= my_stmt_result("SELECT * FROM test_date"); + DIE_UNLESS(row_count == rc); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_date"); + check_stmt(stmt); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + for (count= 0; count < row_count; count++) + { + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0 || rc == MYSQL_DATA_TRUNCATED); + + if (!opt_silent) + fprintf(stdout, "\n"); + for (i= 0; i < array_elements(my_bind); i++) + { + if (!opt_silent) + fprintf(stdout, "\ntime[%d]: %02d-%02d-%02d %02d:%02d:%02d.%02lu", + i, tm[i].year, tm[i].month, tm[i].day, + tm[i].hour, tm[i].minute, tm[i].second, + tm[i].second_part); + DIE_UNLESS(tm[i].year == 0 || tm[i].year == year + count || + (tm[i].year == now_year && + my_bind[i].buffer_type == MYSQL_TYPE_TIME)); + DIE_UNLESS(tm[i].month == 0 || tm[i].month == month + count || + (tm[i].month == now_month && + my_bind[i].buffer_type == MYSQL_TYPE_TIME)); + DIE_UNLESS(tm[i].day == 0 || tm[i].day == day + count || + (tm[i].day == now_day && + my_bind[i].buffer_type == MYSQL_TYPE_TIME)); + + DIE_UNLESS(tm[i].hour == 0 || tm[i].hour == hour+count); + DIE_UNLESS(tm[i].minute == 0 || tm[i].minute == minute+count); + DIE_UNLESS(tm[i].second == 0 || tm[i].second == sec+count); + DIE_UNLESS(tm[i].second_part == 0 || + tm[i].second_part == second_part+count); + } + } + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Test DATE, TIME, DATETIME and TS with MYSQL_TIME conversion */ + +static void test_date() +{ + int rc; + + myheader("test_date"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_date(c1 TIMESTAMP, \ + c2 TIME, \ + c3 DATETIME, \ + c4 DATE)"); + + myquery(rc); + + test_bind_date_conv(5); +} + + +/* Test all time types to DATE and DATE to all types */ + +static void test_date_date() +{ + int rc; + + myheader("test_date_date"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_date(c1 DATE, \ + c2 DATE, \ + c3 DATE, \ + c4 DATE)"); + + myquery(rc); + + test_bind_date_conv(3); +} + + +/* Test all time types to TIME and TIME to all types */ + +static void test_date_time() +{ + int rc; + + myheader("test_date_time"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_date(c1 TIME, \ + c2 TIME, \ + c3 TIME, \ + c4 TIME)"); + + myquery(rc); + + test_bind_date_conv(3); +} + + +/* Test all time types to TIMESTAMP and TIMESTAMP to all types */ + +static void test_date_ts() +{ + int rc; + + myheader("test_date_ts"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_date(c1 TIMESTAMP, \ + c2 TIMESTAMP, \ + c3 TIMESTAMP, \ + c4 TIMESTAMP)"); + + myquery(rc); + + test_bind_date_conv(2); +} + + +/* Test all time types to DATETIME and DATETIME to all types */ + +static void test_date_dt() +{ + int rc; + + myheader("test_date_dt"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_date"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_date(c1 datetime, " + " c2 datetime, c3 datetime, c4 date)"); + myquery(rc); + + test_bind_date_conv(2); +} + +static void test_simple_temporal() { + + MYSQL_STMT *stmt = NULL; + uint rc; + ulong length = 0; + MYSQL_BIND my_bind[4], my_bind2; + my_bool is_null = FALSE; + MYSQL_TIME tm; + char string[100]; + MYSQL_RES *rs; + MYSQL_FIELD *field; + + myheader("test_simple_temporal"); + + /* Initialize param/fetch buffers for data, null flags, lengths */ + memset(&my_bind, 0, sizeof(my_bind)); + memset(&my_bind2, 0, sizeof(my_bind2)); + + /* Initialize the first input parameter */ + my_bind[0].buffer_type = MYSQL_TYPE_DATETIME; + my_bind[0].buffer = &tm; + my_bind[0].is_null = &is_null; + my_bind[0].length = &length; + my_bind[0].buffer_length = sizeof(tm); + + /* Clone the other input parameters */ + my_bind[3] = my_bind[2] = my_bind[1] = my_bind[0]; + + my_bind[1].buffer_type = MYSQL_TYPE_TIMESTAMP; + my_bind[2].buffer_type = MYSQL_TYPE_DATE; + my_bind[3].buffer_type = MYSQL_TYPE_TIME; + + /* Initialize fetch parameter */ + my_bind2.buffer_type = MYSQL_TYPE_STRING; + my_bind2.length = &length; + my_bind2.is_null = &is_null; + my_bind2.buffer_length = sizeof(string); + my_bind2.buffer = string; + + /* Prepare and bind simple SELECT with DATETIME parameter */ + stmt = mysql_simple_prepare(mysql, "SELECT ?"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + rc = mysql_stmt_bind_param(stmt, &my_bind[0]); + check_execute(stmt, rc); + + rc = mysql_stmt_bind_result(stmt, &my_bind2); + check_execute(stmt, rc); + + /* Initialize DATETIME value */ + tm.neg = FALSE; + tm.time_type = MYSQL_TIMESTAMP_DATETIME; + tm.year = 2001; + tm.month = 10; + tm.day = 20; + tm.hour = 10; + tm.minute = 10; + tm.second = 59; + tm.second_part = 500000; + + /* Execute and fetch */ + rc = mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rs = mysql_stmt_result_metadata(stmt); + field = mysql_fetch_fields(rs); + + rc = mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc = mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(field->type == MYSQL_TYPE_DATETIME); + DIE_UNLESS(strcmp(string, "2001-10-20 10:10:59.500000") == 0); + + mysql_free_result(rs); + + mysql_stmt_close(stmt); + + /* Same test with explicit CAST */ + stmt = mysql_simple_prepare(mysql, "SELECT CAST(? AS DATETIME(6))"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + rc = mysql_stmt_bind_param(stmt, &my_bind[0]); + check_execute(stmt, rc); + + rc = mysql_stmt_bind_result(stmt, &my_bind2); + check_execute(stmt, rc); + + /* Execute and fetch */ + rc = mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rs = mysql_stmt_result_metadata(stmt); + field = mysql_fetch_fields(rs); + + rc = mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc = mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(field->type == MYSQL_TYPE_DATETIME); + DIE_UNLESS(strcmp(string, "2001-10-20 10:10:59.500000") == 0); + + mysql_free_result(rs); + + mysql_stmt_close(stmt); + + /* Prepare and bind simple SELECT with TIMESTAMP parameter */ + stmt = mysql_simple_prepare(mysql, "SELECT ?"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + rc = mysql_stmt_bind_param(stmt, &my_bind[1]); + check_execute(stmt, rc); + + rc = mysql_stmt_bind_result(stmt, &my_bind2); + check_execute(stmt, rc); + + /* Initialize TIMESTAMP value */ + tm.neg = FALSE; + tm.time_type = MYSQL_TIMESTAMP_DATETIME; + tm.year = 2001; + tm.month = 10; + tm.day = 20; + tm.hour = 10; + tm.minute = 10; + tm.second = 59; + tm.second_part = 500000; + + /* Execute and fetch */ + rc = mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rs = mysql_stmt_result_metadata(stmt); + field = mysql_fetch_fields(rs); + + rc = mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc = mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(field->type == MYSQL_TYPE_TIMESTAMP); + DIE_UNLESS(strcmp(string, "2001-10-20 10:10:59.500000") == 0); + + mysql_free_result(rs); + + mysql_stmt_close(stmt); + + /* Prepare and bind simple SELECT with DATE parameter */ + stmt = mysql_simple_prepare(mysql, "SELECT ?"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + rc = mysql_stmt_bind_param(stmt, &my_bind[2]); + check_execute(stmt, rc); + + rc = mysql_stmt_bind_result(stmt, &my_bind2); + check_execute(stmt, rc); + + /* Initialize DATE value */ + tm.neg = FALSE; + tm.time_type = MYSQL_TIMESTAMP_DATE; + tm.year = 2001; + tm.month = 10; + tm.day = 20; + tm.hour = 0; + tm.minute = 0; + tm.second = 0; + tm.second_part = 0; + + /* Execute and fetch */ + rc = mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rs = mysql_stmt_result_metadata(stmt); + field = mysql_fetch_fields(rs); + + rc = mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc = mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(field->type == MYSQL_TYPE_DATE); + DIE_UNLESS(strcmp(string, "2001-10-20") == 0); + + mysql_free_result(rs); + + mysql_stmt_close(stmt); + + /* Same test with explicit CAST */ + stmt = mysql_simple_prepare(mysql, "SELECT CAST(? AS DATE)"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + rc = mysql_stmt_bind_param(stmt, &my_bind[2]); + check_execute(stmt, rc); + + rc = mysql_stmt_bind_result(stmt, &my_bind2); + check_execute(stmt, rc); + + /* Execute and fetch */ + rc = mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rs = mysql_stmt_result_metadata(stmt); + field = mysql_fetch_fields(rs); + + rc = mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc = mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(field->type == MYSQL_TYPE_DATE); + DIE_UNLESS(strcmp(string, "2001-10-20") == 0); + + mysql_free_result(rs); + + mysql_stmt_close(stmt); + + /* Prepare and bind simple SELECT with TIME parameter */ + stmt = mysql_simple_prepare(mysql, "SELECT ?"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + rc = mysql_stmt_bind_param(stmt, &my_bind[3]); + check_execute(stmt, rc); + + rc = mysql_stmt_bind_result(stmt, &my_bind2); + check_execute(stmt, rc); + + /* Initialize TIME value */ + tm.neg = FALSE; + tm.time_type = MYSQL_TIMESTAMP_TIME; + tm.year = 0; + tm.month = 0; + tm.day = 0; + tm.hour = 10; + tm.minute = 10; + tm.second = 59; + tm.second_part = 500000; + + /* Execute and fetch */ + rc = mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rs = mysql_stmt_result_metadata(stmt); + field = mysql_fetch_fields(rs); + + rc = mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc = mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(field->type == MYSQL_TYPE_TIME); + DIE_UNLESS(strcmp(string, "10:10:59.500000") == 0); + + mysql_free_result(rs); + + mysql_stmt_close(stmt); + + /* Same test with explicit CAST */ + stmt = mysql_simple_prepare(mysql, "SELECT CAST(? AS TIME(6))"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + rc = mysql_stmt_bind_param(stmt, &my_bind[3]); + check_execute(stmt, rc); + + rc = mysql_stmt_bind_result(stmt, &my_bind2); + check_execute(stmt, rc); + + /* Initialize TIME value */ + tm.neg = FALSE; + tm.time_type = MYSQL_TIMESTAMP_TIME; + tm.year = 0; + tm.month = 0; + tm.day = 0; + tm.hour = 10; + tm.minute = 10; + tm.second = 59; + tm.second_part = 500000; + + /* Execute and fetch */ + rc = mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rs = mysql_stmt_result_metadata(stmt); + field = mysql_fetch_fields(rs); + + rc = mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc = mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(field->type == MYSQL_TYPE_TIME); + DIE_UNLESS(strcmp(string, "10:10:59.500000") == 0); + + mysql_free_result(rs); + + mysql_stmt_close(stmt); +} + + +/* Misc tests to keep pure coverage happy */ + +static void test_pure_coverage() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + int rc; + ulong length; + + myheader("test_pure_coverage"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_pure"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_pure(c1 int, c2 varchar(20))"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "insert into test_pure(c67788) values(10)"); + check_stmt_r(stmt); + + /* Query without params and result should allow to bind 0 arrays */ + stmt= mysql_simple_prepare(mysql, "insert into test_pure(c2) values(10)"); + check_stmt(stmt); + + rc= mysql_stmt_bind_param(stmt, (MYSQL_BIND*)0); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, (MYSQL_BIND*)0); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "insert into test_pure(c2) values(?)"); + check_stmt(stmt); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].length= &length; + my_bind[0].is_null= 0; + my_bind[0].buffer_length= 0; + + my_bind[0].buffer_type= MYSQL_TYPE_GEOMETRY; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute_r(stmt, rc); /* unsupported buffer type */ + + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "select * from test_pure"); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + my_bind[0].buffer_type= MYSQL_TYPE_GEOMETRY; + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); /* MariaDB C/C converts geometry to string */ + + rc= mysql_stmt_store_result(stmt); + DIE_IF(rc); + + rc= mysql_stmt_store_result(stmt); + DIE_UNLESS(rc); /* Old error must be reset first */ + + mysql_stmt_close(stmt); + + mysql_query(mysql, "DROP TABLE test_pure"); +} + + +/* Test for string buffer fetch */ + +static void test_buffers() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + int rc; + ulong length; + my_bool is_null; + char buffer[20]; + + myheader("test_buffers"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_buffer"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_buffer(str varchar(20))"); + myquery(rc); + + rc= mysql_query(mysql, "insert into test_buffer values('MySQL')\ + , ('Database'), ('Open-Source'), ('Popular')"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "select str from test_buffer"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero(buffer, sizeof(buffer)); /* Avoid overruns in printf() */ + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].length= &length; + my_bind[0].is_null= &is_null; + my_bind[0].buffer_length= 1; + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)buffer; + my_bind[0].error= &my_bind[0].error_value; + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + buffer[1]= 'X'; + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED); + DIE_UNLESS(my_bind[0].error_value); + if (!opt_silent) + fprintf(stdout, "\n data: %s (%lu)", buffer, length); + DIE_UNLESS(buffer[0] == 'M'); + DIE_UNLESS(buffer[1] == 'X'); + DIE_UNLESS(length == 5); + + my_bind[0].buffer_length= 8; + rc= mysql_stmt_bind_result(stmt, my_bind);/* re-bind */ + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n data: %s (%lu)", buffer, length); + DIE_UNLESS(strncmp(buffer, "Database", 8) == 0); + DIE_UNLESS(length == 8); + + my_bind[0].buffer_length= 12; + rc= mysql_stmt_bind_result(stmt, my_bind);/* re-bind */ + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n data: %s (%lu)", buffer, length); + DIE_UNLESS(strcmp(buffer, "Open-Source") == 0); + DIE_UNLESS(length == 11); + + my_bind[0].buffer_length= 6; + rc= mysql_stmt_bind_result(stmt, my_bind);/* re-bind */ + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED); + DIE_UNLESS(my_bind[0].error_value); + if (!opt_silent) + fprintf(stdout, "\n data: %s (%lu)", buffer, length); + DIE_UNLESS(strncmp(buffer, "Popula", 6) == 0); + DIE_UNLESS(length == 7); + + mysql_stmt_close(stmt); +} + + +/* Test the direct query execution in the middle of open stmts */ + +static void test_open_direct() +{ + MYSQL_STMT *stmt; + MYSQL_RES *result; + int rc; + + myheader("test_open_direct"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_open_direct"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_open_direct(id int, name char(6))"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "INSERT INTO test_open_direct values(10, 'mysql')"); + check_stmt(stmt); + + rc= mysql_query(mysql, "SELECT * FROM test_open_direct"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 0); + mysql_free_result(result); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_st_affected_rows(stmt, 1); + + rc= mysql_query(mysql, "SELECT * FROM test_open_direct"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_st_affected_rows(stmt, 1); + + rc= mysql_query(mysql, "SELECT * FROM test_open_direct"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 2); + mysql_free_result(result); + + mysql_stmt_close(stmt); + + /* run a direct query in the middle of a fetch */ + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_open_direct"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "INSERT INTO test_open_direct(id) VALUES(20)"); + myquery_r(rc); + + rc= mysql_stmt_close(stmt); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "INSERT INTO test_open_direct(id) VALUES(20)"); + myquery(rc); + + /* run a direct query with store result */ + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_open_direct"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "drop table test_open_direct"); + myquery(rc); + + rc= mysql_stmt_close(stmt); + check_execute(stmt, rc); +} + + +/* Test fetch without prior bound buffers */ + +static void test_fetch_nobuffs() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[4]; + char str[4][50]; + int rc; + + myheader("test_fetch_nobuffs"); + + stmt= mysql_simple_prepare(mysql, "SELECT DATABASE(), CURRENT_USER(), \ + CURRENT_DATE(), CURRENT_TIME()"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= 0; + while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + rc++; + + if (!opt_silent) + fprintf(stdout, "\n total rows : %d", rc); + DIE_UNLESS(rc == 1); + + bzero((char*) my_bind, sizeof(MYSQL_BIND)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)str[0]; + my_bind[0].buffer_length= sizeof(str[0]); + my_bind[1]= my_bind[2]= my_bind[3]= my_bind[0]; + my_bind[1].buffer= (void *)str[1]; + my_bind[2].buffer= (void *)str[2]; + my_bind[3].buffer= (void *)str[3]; + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= 0; + while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + { + rc++; + if (!opt_silent) + { + fprintf(stdout, "\n CURRENT_DATABASE(): %s", str[0]); + fprintf(stdout, "\n CURRENT_USER() : %s", str[1]); + fprintf(stdout, "\n CURRENT_DATE() : %s", str[2]); + fprintf(stdout, "\n CURRENT_TIME() : %s", str[3]); + } + } + if (!opt_silent) + fprintf(stdout, "\n total rows : %d", rc); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); +} + + +/* Test a misc bug */ + +static void test_ushort_bug() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[4]; + ushort short_value; + uint32 long_value; + ulong s_length, l_length, ll_length, t_length; + ulonglong longlong_value; + int rc; + uchar tiny_value; + char llbuf[22]; + myheader("test_ushort_bug"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ushort"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_ushort(a smallint unsigned, \ + b smallint unsigned, \ + c smallint unsigned, \ + d smallint unsigned)"); + myquery(rc); + + rc= mysql_query(mysql, + "INSERT INTO test_ushort VALUES(35999, 35999, 35999, 200)"); + myquery(rc); + + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_ushort"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_SHORT; + my_bind[0].buffer= (void *)&short_value; + my_bind[0].is_unsigned= TRUE; + my_bind[0].length= &s_length; + + my_bind[1].buffer_type= MYSQL_TYPE_LONG; + my_bind[1].buffer= (void *)&long_value; + my_bind[1].length= &l_length; + + my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG; + my_bind[2].buffer= (void *)&longlong_value; + my_bind[2].length= &ll_length; + + my_bind[3].buffer_type= MYSQL_TYPE_TINY; + my_bind[3].buffer= (void *)&tiny_value; + my_bind[3].is_unsigned= TRUE; + my_bind[3].length= &t_length; + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + { + fprintf(stdout, "\n ushort : %d (%ld)", short_value, s_length); + fprintf(stdout, "\n ulong : %lu (%ld)", (ulong) long_value, l_length); + fprintf(stdout, "\n longlong : %s (%ld)", llstr(longlong_value, llbuf), + ll_length); + fprintf(stdout, "\n tinyint : %d (%ld)", tiny_value, t_length); + } + + DIE_UNLESS(short_value == 35999); + DIE_UNLESS(s_length == 2); + + DIE_UNLESS(long_value == 35999); + DIE_UNLESS(l_length == 4); + + DIE_UNLESS(longlong_value == 35999); + DIE_UNLESS(ll_length == 8); + + DIE_UNLESS(tiny_value == 200); + DIE_UNLESS(t_length == 1); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Test a misc smallint-signed conversion bug */ + +static void test_sshort_bug() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[4]; + short short_value; + int32 long_value; + ulong s_length, l_length, ll_length, t_length; + ulonglong longlong_value; + int rc; + uchar tiny_value; + char llbuf[22]; + + myheader("test_sshort_bug"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_sshort"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_sshort(a smallint signed, \ + b smallint signed, \ + c smallint unsigned, \ + d smallint unsigned)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_sshort VALUES(-5999, -5999, 35999, 200)"); + myquery(rc); + + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_sshort"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_SHORT; + my_bind[0].buffer= (void *)&short_value; + my_bind[0].length= &s_length; + + my_bind[1].buffer_type= MYSQL_TYPE_LONG; + my_bind[1].buffer= (void *)&long_value; + my_bind[1].length= &l_length; + + my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG; + my_bind[2].buffer= (void *)&longlong_value; + my_bind[2].length= &ll_length; + + my_bind[3].buffer_type= MYSQL_TYPE_TINY; + my_bind[3].buffer= (void *)&tiny_value; + my_bind[3].is_unsigned= TRUE; + my_bind[3].length= &t_length; + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + { + fprintf(stdout, "\n sshort : %d (%ld)", short_value, s_length); + fprintf(stdout, "\n slong : %ld (%ld)", (long) long_value, l_length); + fprintf(stdout, "\n longlong : %s (%ld)", llstr(longlong_value, llbuf), + ll_length); + fprintf(stdout, "\n tinyint : %d (%ld)", tiny_value, t_length); + } + + DIE_UNLESS(short_value == -5999); + DIE_UNLESS(s_length == 2); + + DIE_UNLESS(long_value == -5999); + DIE_UNLESS(l_length == 4); + + DIE_UNLESS(longlong_value == 35999); + DIE_UNLESS(ll_length == 8); + + DIE_UNLESS(tiny_value == 200); + DIE_UNLESS(t_length == 1); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Test a misc tinyint-signed conversion bug */ + +static void test_stiny_bug() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[4]; + short short_value; + int32 long_value; + ulong s_length, l_length, ll_length, t_length; + ulonglong longlong_value; + int rc; + uchar tiny_value; + char llbuf[22]; + + myheader("test_stiny_bug"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_stiny"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_stiny(a tinyint signed, \ + b tinyint signed, \ + c tinyint unsigned, \ + d tinyint unsigned)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_stiny VALUES(-128, -127, 255, 0)"); + myquery(rc); + + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_stiny"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_SHORT; + my_bind[0].buffer= (void *)&short_value; + my_bind[0].length= &s_length; + + my_bind[1].buffer_type= MYSQL_TYPE_LONG; + my_bind[1].buffer= (void *)&long_value; + my_bind[1].length= &l_length; + + my_bind[2].buffer_type= MYSQL_TYPE_LONGLONG; + my_bind[2].buffer= (void *)&longlong_value; + my_bind[2].length= &ll_length; + + my_bind[3].buffer_type= MYSQL_TYPE_TINY; + my_bind[3].buffer= (void *)&tiny_value; + my_bind[3].length= &t_length; + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + { + fprintf(stdout, "\n sshort : %d (%ld)", short_value, s_length); + fprintf(stdout, "\n slong : %ld (%ld)", (long) long_value, l_length); + fprintf(stdout, "\n longlong : %s (%ld)", llstr(longlong_value, llbuf), + ll_length); + fprintf(stdout, "\n tinyint : %d (%ld)", tiny_value, t_length); + } + + DIE_UNLESS(short_value == -128); + DIE_UNLESS(s_length == 2); + + DIE_UNLESS(long_value == -127); + DIE_UNLESS(l_length == 4); + + DIE_UNLESS(longlong_value == 255); + DIE_UNLESS(ll_length == 8); + + DIE_UNLESS(tiny_value == 0); + DIE_UNLESS(t_length == 1); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Test misc field information, bug: #74 */ + +static void test_field_misc() +{ + MYSQL_STMT *stmt; + MYSQL_RES *result; + int rc; + + myheader("test_field_misc"); + + rc= mysql_query(mysql, "SELECT @@autocommit"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + + verify_prepare_field(result, 0, + "@@autocommit", "", /* field and its org name */ + MYSQL_TYPE_LONGLONG, /* field type */ + "", "", /* table and its org name */ + "", 1, 0); /* db name, length(its bool flag)*/ + + mysql_free_result(result); + + stmt= mysql_simple_prepare(mysql, "SELECT @@autocommit"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + result= mysql_stmt_result_metadata(stmt); + mytest(result); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + verify_prepare_field(result, 0, + "@@autocommit", "", /* field and its org name */ + MYSQL_TYPE_LONGLONG, /* field type */ + "", "", /* table and its org name */ + "", 1, 0); /* db name, length(its bool flag)*/ + + mysql_free_result(result); + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "SELECT @@max_error_count"); + check_stmt(stmt); + + result= mysql_stmt_result_metadata(stmt); + mytest(result); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + verify_prepare_field(result, 0, + "@@max_error_count", "", /* field and its org name */ + MYSQL_TYPE_LONGLONG, /* field type */ + "", "", /* table and its org name */ + /* db name, length */ + "", MY_INT64_NUM_DECIMAL_DIGITS , 0); + + mysql_free_result(result); + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "SELECT @@max_allowed_packet"); + check_stmt(stmt); + + result= mysql_stmt_result_metadata(stmt); + mytest(result); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(1 == my_process_stmt_result(stmt)); + + verify_prepare_field(result, 0, + "@@max_allowed_packet", "", /* field and its org name */ + MYSQL_TYPE_LONGLONG, /* field type */ + "", "", /* table and its org name */ + /* db name, length */ + "", MY_INT64_NUM_DECIMAL_DIGITS, 0); + + mysql_free_result(result); + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "SELECT @@sql_warnings"); + check_stmt(stmt); + + result= mysql_stmt_result_metadata(stmt); + mytest(result); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + verify_prepare_field(result, 0, + "@@sql_warnings", "", /* field and its org name */ + MYSQL_TYPE_LONGLONG, /* field type */ + "", "", /* table and its org name */ + "", 1, 0); /* db name, length */ + + mysql_free_result(result); + mysql_stmt_close(stmt); +} + + +/* + Test SET OPTION feature with prepare stmts + bug #85 (reported by mark@mysql.com) +*/ + +static void test_set_option() +{ + MYSQL_STMT *stmt; + MYSQL_RES *result; + int rc; + + myheader("test_set_option"); + + mysql_autocommit(mysql, TRUE); + + /* LIMIT the rows count to 2 */ + rc= mysql_query(mysql, "SET SQL_SELECT_LIMIT= 2"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_limit"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_limit(a tinyint)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_limit VALUES(10), (20), (30), (40)"); + myquery(rc); + + if (!opt_silent) + fprintf(stdout, "\n with SQL_SELECT_LIMIT= 2 (direct)"); + rc= mysql_query(mysql, "SELECT * FROM test_limit"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 2); + + mysql_free_result(result); + + if (!opt_silent) + fprintf(stdout, "\n with SQL_SELECT_LIMIT=2 (prepare)"); + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_limit"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 2); + + mysql_stmt_close(stmt); + + /* RESET the LIMIT the rows count to 0 */ + if (!opt_silent) + fprintf(stdout, "\n with SQL_SELECT_LIMIT=DEFAULT (prepare)"); + rc= mysql_query(mysql, "SET SQL_SELECT_LIMIT=DEFAULT"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_limit"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 4); + + mysql_stmt_close(stmt); +} + +#ifdef EMBEDDED_LIBRARY +static void test_embedded_start_stop() +{ + MYSQL *mysql_emb=NULL; + int i, j; + int argc= original_argc; // Start with the original args + char **argv, **my_argv; + char test_name[]= "test_embedded_start_stop"; +#define EMBEDDED_RESTARTS 64 + + myheader("test_embedded_start_stop"); + + /* Must stop the main embedded server, since we use the same config. */ + client_disconnect(mysql); /* disconnect from server */ + free_defaults(defaults_argv); + mysql_server_end(); + /* Free everything allocated by my_once_alloc */ + my_end(0); + + /* + Use a copy of the original arguments. + The arguments will be altered when reading the configs and parsing + options. + */ + my_argv= malloc((argc + 1) * sizeof(char*)); + if (!my_argv) + exit(1); + + /* Test restarting the embedded library many times. */ + for (i= 1; i <= EMBEDDED_RESTARTS; i++) + { + argv= my_argv; + argv[0]= test_name; + for (j= 1; j < argc; j++) + argv[j]= original_argv[j]; + + /* Initialize everything again. */ + MY_INIT(argv[0]); + + /* Load the client defaults from the .cnf file[s]. */ + load_defaults_or_exit("my", client_test_load_default_groups, &argc, &argv); + + /* Parse the options (including the ones given from defaults files). */ + get_options(&argc, &argv); + + /* mysql_library_init is the same as mysql_server_init. */ + if (mysql_library_init(embedded_server_arg_count, + embedded_server_args, + (char**) embedded_server_groups)) + { + myerror("mysql_library_init failed"); + exit(1); + } + + /* Create a client connection. */ + if (!(mysql_emb= mysql_client_init(NULL))) + { + myerror("mysql_client_init failed"); + exit(1); + } + + /* Connect it and see if we can use the database. */ + if (!(mysql_real_connect(mysql_emb, opt_host, opt_user, + opt_password, current_db, 0, + NULL, 0))) + { + myerror("mysql_real_connect failed"); + } + + /* Close the client connection */ + mysql_close(mysql_emb); + mysql_emb = NULL; + /* Free arguments allocated for defaults files. */ + free_defaults(defaults_argv); + /* mysql_library_end is a define for mysql_server_end. */ + mysql_library_end(); + /* Free everything allocated by my_once_alloc */ + my_end(0); + } + + argc= original_argc; + argv= my_argv; + argv[0]= test_name; + for (j= 1; j < argc; j++) + argv[j]= original_argv[j]; + + MY_INIT(argv[0]); + + load_defaults_or_exit("my", client_test_load_default_groups, &argc, &argv); + get_options(&argc, &argv); + + /* Must start the main embedded server again after the test. */ + if (mysql_server_init(embedded_server_arg_count, + embedded_server_args, + (char**) embedded_server_groups)) + DIE("Can't initialize MariaDB server"); + + /* connect to server with no flags, default protocol, auto reconnect true */ + mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1); + free(my_argv); +} +#endif /* EMBEDDED_LIBRARY */ + + +/* + Test a misc GRANT option + bug #89 (reported by mark@mysql.com) +*/ + +#ifndef EMBEDDED_LIBRARY +static void test_prepare_grant() +{ + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_prepare_grant"); + + mysql_autocommit(mysql, TRUE); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_grant"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_grant(a tinyint primary key auto_increment)"); + myquery(rc); + + strxmov(query, "GRANT INSERT, UPDATE, SELECT ON ", current_db, + ".test_grant TO 'test_grant'@", + opt_host ? opt_host : "'localhost'", NullS); + + if (mysql_query(mysql, query)) + { + myerror("GRANT failed"); + + /* + If server started with --skip-grant-tables, skip this test, else + exit to indicate an error + + ER_UNKNOWN_COM_ERROR= 1047 + */ + if (mysql_errno(mysql) != 1047) + exit(1); + } + else + { + MYSQL *org_mysql= mysql, *lmysql; + MYSQL_STMT *stmt; + + if (!opt_silent) + fprintf(stdout, "\n Establishing a test connection ..."); + if (!(lmysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + exit(1); + } + if (!(mysql_real_connect(lmysql, opt_host, "test_grant", + "", current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + mysql_close(lmysql); + exit(1); + } + mysql_options(lmysql, MYSQL_OPT_RECONNECT, &my_true); + if (!opt_silent) + fprintf(stdout, "OK"); + + mysql= lmysql; + rc= mysql_query(mysql, "INSERT INTO test_grant VALUES(NULL)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_grant(a) VALUES(NULL)"); + myquery(rc); + + execute_prepare_query("INSERT INTO test_grant(a) VALUES(NULL)", 1); + execute_prepare_query("INSERT INTO test_grant VALUES(NULL)", 1); + execute_prepare_query("UPDATE test_grant SET a=9 WHERE a=1", 1); + rc= my_stmt_result("SELECT a FROM test_grant"); + DIE_UNLESS(rc == 4); + + /* Both DELETE expected to fail as user does not have DELETE privs */ + + rc= mysql_query(mysql, "DELETE FROM test_grant"); + myquery_r(rc); + + stmt= mysql_simple_prepare(mysql, "DELETE FROM test_grant"); + check_stmt_r(stmt); + + rc= my_stmt_result("SELECT * FROM test_grant"); + DIE_UNLESS(rc == 4); + + mysql_close(lmysql); + mysql= org_mysql; + + rc= mysql_query(mysql, "delete from mysql.user where User='test_grant'"); + myquery(rc); + DIE_UNLESS(1 == mysql_affected_rows(mysql)); + + rc= mysql_query(mysql, "delete from mysql.tables_priv where User='test_grant'"); + myquery(rc); + DIE_UNLESS(1 == mysql_affected_rows(mysql)); + + } +} +#endif /* EMBEDDED_LIBRARY */ + +/* + Test a crash when invalid/corrupted .frm is used in the + SHOW TABLE STATUS + bug #93 (reported by serg@mysql.com). +*/ + +static void test_frm_bug() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + MYSQL_RES *result; + MYSQL_ROW row; + FILE *test_file; + char data_dir[FN_REFLEN]; + char test_frm[FN_REFLEN]; + int rc; + + myheader("test_frm_bug"); + + mysql_autocommit(mysql, TRUE); + + rc= mysql_query(mysql, "drop table if exists test_frm_bug"); + myquery(rc); + + rc= mysql_query(mysql, "flush tables"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "show variables like 'datadir'"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= data_dir; + my_bind[0].buffer_length= FN_REFLEN; + my_bind[1]= my_bind[0]; + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n data directory: %s", data_dir); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + strxmov(test_frm, data_dir, "/", current_db, "/", "test_frm_bug.frm", NullS); + + if (!opt_silent) + fprintf(stdout, "\n test_frm: %s", test_frm); + + if (!(test_file= my_fopen(test_frm, (int) (O_RDWR | O_CREAT), MYF(MY_WME)))) + { + fprintf(stdout, "\n ERROR: my_fopen failed for '%s'", test_frm); + fprintf(stdout, "\n test cancelled"); + exit(1); + } + if (!opt_silent) + fprintf(test_file, "this is a junk file for test"); + + rc= mysql_query(mysql, "SHOW TABLE STATUS like 'test_frm_bug'"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result);/* It can't be NULL */ + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + + mysql_data_seek(result, 0); + + row= mysql_fetch_row(result); + mytest(row); + + if (!opt_silent) + fprintf(stdout, "\n Comment: %s", row[17]); + DIE_UNLESS(row[17] != 0); + + mysql_free_result(result); + mysql_stmt_close(stmt); + + my_fclose(test_file, MYF(0)); + mysql_query(mysql, "drop table if exists test_frm_bug"); +} + + +/* Test DECIMAL conversion */ + +static void test_decimal_bug() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + char data[30]; + int rc; + my_bool is_null; + + myheader("test_decimal_bug"); + + mysql_autocommit(mysql, TRUE); + + rc= mysql_query(mysql, "drop table if exists test_decimal_bug"); + myquery(rc); + + rc= mysql_query(mysql, "create table test_decimal_bug(c1 decimal(10, 2))"); + myquery(rc); + + rc= mysql_query(mysql, "insert into test_decimal_bug value(8), (10.22), (5.61)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "select c1 from test_decimal_bug where c1= ?"); + check_stmt(stmt); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_NEWDECIMAL; + my_bind[0].buffer= (void *)data; + my_bind[0].buffer_length= 25; + my_bind[0].is_null= &is_null; + + is_null= 0; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + memset(data, 0, sizeof data); + strmov(data, "8.0"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + data[0]= 0; + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n data: %s", data); + DIE_UNLESS(strcmp(data, "8.00") == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + strmov(data, "5.61"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + data[0]= 0; + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n data: %s", data); + DIE_UNLESS(strcmp(data, "5.61") == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + is_null= 1; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + strmov(data, "10.22"); is_null= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + data[0]= 0; + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n data: %s", data); + DIE_UNLESS(strcmp(data, "10.22") == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/* Test EXPLAIN bug (#115, reported by mark@mysql.com & georg@php.net). */ + +static void test_explain_bug() +{ + MYSQL_STMT *stmt; + MYSQL_RES *result; + int rc; + + myheader("test_explain_bug"); + + mysql_autocommit(mysql, TRUE); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_explain"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_explain(id int, name char(2))"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "explain test_explain"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 2); + + result= mysql_stmt_result_metadata(stmt); + mytest(result); + + if (!opt_silent) + fprintf(stdout, "\n total fields in the result: %d", + mysql_num_fields(result)); + DIE_UNLESS(6 == mysql_num_fields(result)); + + verify_prepare_field(result, 0, "Field", "COLUMN_NAME", + mysql_get_server_version(mysql) <= 50000 ? + MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, + 0, 0, "information_schema", 64, 0); + + verify_prepare_field(result, 1, "Type", "COLUMN_TYPE", MYSQL_TYPE_BLOB, + 0, 0, "information_schema", 0, 0); + + verify_prepare_field(result, 2, "Null", "IS_NULLABLE", + mysql_get_server_version(mysql) <= 50000 ? + MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, + 0, 0, "information_schema", 3, 0); + + verify_prepare_field(result, 3, "Key", "COLUMN_KEY", + mysql_get_server_version(mysql) <= 50000 ? + MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, + 0, 0, "information_schema", 3, 0); + + if ( mysql_get_server_version(mysql) >= 50027 ) + { + /* The patch for bug#23037 changes column type of DEAULT to blob */ + verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT", + MYSQL_TYPE_BLOB, 0, 0, "information_schema", 0, 0); + } + else + { + verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT", + mysql_get_server_version(mysql) >= 50027 ? + MYSQL_TYPE_BLOB : + mysql_get_server_version(mysql) <= 50000 ? + MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, + 0, 0, "information_schema", + mysql_get_server_version(mysql) >= 50027 ? 0 :64, 0); + } + + verify_prepare_field(result, 5, "Extra", "EXTRA", + mysql_get_server_version(mysql) <= 50000 ? + MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, + 0, 0, "information_schema", 80, 0); + + mysql_free_result(result); + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "explain select id, name FROM test_explain"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + result= mysql_stmt_result_metadata(stmt); + mytest(result); + + if (!opt_silent) + fprintf(stdout, "\n total fields in the result: %d", + mysql_num_fields(result)); + DIE_UNLESS(10 == mysql_num_fields(result)); + + verify_prepare_field(result, 0, "id", "", MYSQL_TYPE_LONGLONG, + "", "", "", 3, 0); + + verify_prepare_field(result, 1, "select_type", "", MYSQL_TYPE_VAR_STRING, + "", "", "", 19, 0); + + verify_prepare_field(result, 2, "table", "", MYSQL_TYPE_VAR_STRING, + "", "", "", NAME_CHAR_LEN, 0); + + verify_prepare_field(result, 3, "type", "", MYSQL_TYPE_VAR_STRING, + "", "", "", 10, 0); + + verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING, + "", "", "", NAME_CHAR_LEN*MAX_KEY, 0); + + verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING, + "", "", "", NAME_CHAR_LEN, 0); + + if (mysql_get_server_version(mysql) <= 50000) + { + verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_LONGLONG, "", + "", "", 3, 0); + } + else + { + verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING, "", + "", "", NAME_CHAR_LEN*MAX_KEY, 0); + } + + /* The length of this may verify between MariaDB versions (1024 / 2048) */ + verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING, + "", "", "", NAME_CHAR_LEN * HA_MAX_KEY_SEG, 0); + + verify_prepare_field(result, 8, "rows", "", MYSQL_TYPE_VAR_STRING, + "", "", "", NAME_CHAR_LEN, 0); + + verify_prepare_field(result, 9, "Extra", "", MYSQL_TYPE_VAR_STRING, + "", "", "", 255, 0); + + mysql_free_result(result); + mysql_stmt_close(stmt); +} + +#ifdef NOT_YET_WORKING + +/* + Test math functions. + Bug #148 (reported by salle@mysql.com). +*/ + +#define myerrno(n) check_errcode(n) + +static void check_errcode(const unsigned int err) +{ + if (!opt_silent || mysql_errno(mysql) != err) + { + if (mysql->server_version) + fprintf(stdout, "\n [MySQL-%s]", mysql->server_version); + else + fprintf(stdout, "\n [MySQL]"); + fprintf(stdout, "[%d] %s\n", mysql_errno(mysql), mysql_error(mysql)); + } + DIE_UNLESS(mysql_errno(mysql) == err); +} + + +static void test_drop_temp() +{ + int rc; + + myheader("test_drop_temp"); + + rc= mysql_query(mysql, "DROP DATABASE IF EXISTS test_drop_temp_db"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE DATABASE test_drop_temp_db"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_drop_temp_db.t1(c1 int, c2 char(1))"); + myquery(rc); + + rc= mysql_query(mysql, "delete from mysql.db where Db='test_drop_temp_db'"); + myquery(rc); + + rc= mysql_query(mysql, "delete from mysql.db where Db='test_drop_temp_db'"); + myquery(rc); + + strxmov(query, "GRANT SELECT, USAGE, DROP ON test_drop_temp_db.* TO test_temp@", + opt_host ? opt_host : "localhost", NullS); + + if (mysql_query(mysql, query)) + { + myerror("GRANT failed"); + + /* + If server started with --skip-grant-tables, skip this test, else + exit to indicate an error + + ER_UNKNOWN_COM_ERROR= 1047 + */ + if (mysql_errno(mysql) != 1047) + exit(1); + } + else + { + MYSQL *org_mysql= mysql, *lmysql; + + if (!opt_silent) + fprintf(stdout, "\n Establishing a test connection ..."); + if (!(lmysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + exit(1); + } + + rc= mysql_query(mysql, "flush privileges"); + myquery(rc); + + if (!(mysql_real_connect(lmysql, opt_host ? opt_host : "localhost", "test_temp", + "", "test_drop_temp_db", opt_port, + opt_unix_socket, 0))) + { + mysql= lmysql; + myerror("connection failed"); + mysql_close(lmysql); + exit(1); + } + mysql_options(lmysql, MYSQL_OPT_RECONNECT, &my_true); + if (!opt_silent) + fprintf(stdout, "OK"); + + mysql= lmysql; + rc= mysql_query(mysql, "INSERT INTO t1 VALUES(10, 'C')"); + myerrno((uint)1142); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myerrno((uint)1142); + + mysql= org_mysql; + rc= mysql_query(mysql, "CREATE TEMPORARY TABLE test_drop_temp_db.t1(c1 int)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TEMPORARY TABLE test_drop_temp_db.t2 LIKE test_drop_temp_db.t1"); + myquery(rc); + + mysql= lmysql; + + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + myquery_r(rc); + + rc= mysql_query(mysql, "DROP TEMPORARY TABLE t1"); + myquery_r(rc); + + rc= mysql_query(mysql, "DROP TEMPORARY TABLE t2"); + myquery_r(rc); + + mysql_close(lmysql); + mysql= org_mysql; + + rc= mysql_query(mysql, "drop database test_drop_temp_db"); + myquery(rc); + DIE_UNLESS(1 == mysql_affected_rows(mysql)); + + rc= mysql_query(mysql, "delete from mysql.user where User='test_temp'"); + myquery(rc); + DIE_UNLESS(1 == mysql_affected_rows(mysql)); + + + rc= mysql_query(mysql, "delete from mysql.tables_priv where User='test_temp'"); + myquery(rc); + DIE_UNLESS(1 == mysql_affected_rows(mysql)); + } +} +#endif + + +/* Test warnings for cuted rows */ + +static void test_cuted_rows() +{ + int rc, count; + MYSQL_RES *result; + + myheader("test_cuted_rows"); + + mysql_query(mysql, "DROP TABLE if exists t1"); + mysql_query(mysql, "DROP TABLE if exists t2"); + + rc= mysql_query(mysql, "CREATE TABLE t1(c1 tinyint)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2(c1 int not null)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 values(10), (NULL), (NULL)"); + myquery(rc); + + count= mysql_warning_count(mysql); + if (!opt_silent) + fprintf(stdout, "\n total warnings: %d", count); + DIE_UNLESS(count == 0); + + rc= mysql_query(mysql, "INSERT INTO t2 SELECT * FROM t1"); + myquery(rc); + + count= mysql_warning_count(mysql); + if (!opt_silent) + fprintf(stdout, "\n total warnings: %d", count); + DIE_UNLESS(count == 2); + + rc= mysql_query(mysql, "SHOW WARNINGS"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 2); + mysql_free_result(result); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES('junk'), (876789)"); + myquery(rc); + + count= mysql_warning_count(mysql); + if (!opt_silent) + fprintf(stdout, "\n total warnings: %d", count); + DIE_UNLESS(count == 2); + + rc= mysql_query(mysql, "SHOW WARNINGS"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 2); + mysql_free_result(result); +} + + +/* Test update/binary logs */ + +static void test_logs() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + char data[255]; + ulong length; + int rc; + short id; + + myheader("test_logs"); + + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_logs"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_logs(id smallint, name varchar(20))"); + myquery(rc); + + strmov((char *)data, "INSERT INTO test_logs VALUES(?, ?)"); + stmt= mysql_simple_prepare(mysql, data); + check_stmt(stmt); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_SHORT; + my_bind[0].buffer= (void *)&id; + + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void *)&data; + my_bind[1].buffer_length= 255; + my_bind[1].length= &length; + + id= 9876; + length= (ulong)(strmov((char *)data, "MySQL - Open Source Database")- data); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + strmov((char *)data, "'"); + length= 1; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + strmov((char *)data, "\""); + length= 1; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + length= (ulong)(strmov((char *)data, "my\'sql\'")-data); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + length= (ulong)(strmov((char *)data, "my\"sql\"")-data); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + strmov((char *)data, "INSERT INTO test_logs VALUES(20, 'mysql')"); + stmt= mysql_simple_prepare(mysql, data); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + strmov((char *)data, "SELECT * FROM test_logs WHERE id=?"); + stmt= mysql_simple_prepare(mysql, data); + check_stmt(stmt); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + my_bind[1].buffer_length= 255; + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + { + fprintf(stdout, "id : %d\n", id); + fprintf(stdout, "name : %s(%ld)\n", data, length); + } + + DIE_UNLESS(id == 9876); + DIE_UNLESS(length == 19 || length == 20); /* Due to VARCHAR(20) */ + DIE_UNLESS(is_prefix(data, "MySQL - Open Source") == 1); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n name : %s(%ld)", data, length); + + DIE_UNLESS(length == 1); + DIE_UNLESS(strcmp(data, "'") == 0); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n name : %s(%ld)", data, length); + + DIE_UNLESS(length == 1); + DIE_UNLESS(strcmp(data, "\"") == 0); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n name : %s(%ld)", data, length); + + DIE_UNLESS(length == 7); + DIE_UNLESS(strcmp(data, "my\'sql\'") == 0); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n name : %s(%ld)", data, length); + + DIE_UNLESS(length == 7); + /*DIE_UNLESS(strcmp(data, "my\"sql\"") == 0); */ + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE test_logs"); + myquery(rc); +} + + +/* Test 'n' statements create and close */ + +static void test_nstmts() +{ + MYSQL_STMT *stmt; + char query[255]; + int rc; + static uint i, total_stmts= 2000; + MYSQL_BIND my_bind[1]; + + myheader("test_nstmts"); + + mysql_autocommit(mysql, TRUE); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_nstmts"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_nstmts(id int)"); + myquery(rc); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer= (void *)&i; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + + for (i= 0; i < total_stmts; i++) + { + if (!opt_silent) + fprintf(stdout, "\r stmt: %d", i); + + strmov(query, "insert into test_nstmts values(?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + } + + stmt= mysql_simple_prepare(mysql, " select count(*) from test_nstmts"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + i= 0; + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n total rows: %d", i); + DIE_UNLESS( i == total_stmts); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE test_nstmts"); + myquery(rc); +} + + +/* Test stmt seek() functions */ + +static void test_fetch_seek() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[3]; + MYSQL_ROW_OFFSET row; + int rc; + int32 c1; + char c2[11], c3[20]; + + myheader("test_fetch_seek"); + rc= mysql_query(mysql, "drop table if exists t1"); + + myquery(rc); + + rc= mysql_query(mysql, "create table t1(c1 int primary key auto_increment, c2 char(10), c3 timestamp)"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1(c2) values('venu'), ('mysql'), ('open'), ('source')"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "select * from t1"); + check_stmt(stmt); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&c1; + + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void *)c2; + my_bind[1].buffer_length= sizeof(c2); + + my_bind[2]= my_bind[1]; + my_bind[2].buffer= (void *)c3; + my_bind[2].buffer_length= sizeof(c3); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 0: %ld, %s, %s", (long) c1, c2, c3); + + row= mysql_stmt_row_tell(stmt); + + row= mysql_stmt_row_seek(stmt, row); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 2: %ld, %s, %s", (long) c1, c2, c3); + + row= mysql_stmt_row_seek(stmt, row); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 2: %ld, %s, %s", (long) c1, c2, c3); + + mysql_stmt_data_seek(stmt, 0); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 0: %ld, %s, %s", (long) c1, c2, c3); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + myquery(mysql_query(mysql, "drop table t1")); +} + + +/* Test mysql_stmt_fetch_column() with offset */ + +static void test_fetch_offset() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + char data[11]; + ulong length; + int rc; + my_bool is_null; + + + myheader("test_fetch_offset"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1(a char(10))"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1 values('abcdefghij'), (null)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "select * from t1"); + check_stmt(stmt); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)data; + my_bind[0].buffer_length= 11; + my_bind[0].is_null= &is_null; + my_bind[0].length= &length; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0); + check_execute_r(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + data[0]= '\0'; + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 1: %s (%ld)", data, length); + DIE_UNLESS(strncmp(data, "abcd", 4) == 0 && length == 10); + + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 5); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 1: %s (%ld)", data, length); + DIE_UNLESS(strncmp(data, "fg", 2) == 0 && length == 10); + + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 9); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 0: %s (%ld)", data, length); + DIE_UNLESS(strncmp(data, "j", 1) == 0 && length == 10); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + is_null= 0; + + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0); + check_execute(stmt, rc); + + DIE_UNLESS(is_null == 1); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0); + check_execute_r(stmt, rc); + + mysql_stmt_close(stmt); + + myquery(mysql_query(mysql, "drop table t1")); +} + + +/* Test mysql_stmt_fetch_column() */ + +static void test_fetch_column() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + char c2[20], bc2[20]; + ulong l1, l2, bl1, bl2; + int rc, c1, bc1; + + myheader("test_fetch_column"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1(c1 int primary key auto_increment, c2 char(10))"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1(c2) values('venu'), ('mysql')"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "select * from t1 order by c2 desc"); + check_stmt(stmt); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&bc1; + my_bind[0].buffer_length= 0; + my_bind[0].is_null= 0; + my_bind[0].length= &bl1; + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void *)bc2; + my_bind[1].buffer_length= 7; + my_bind[1].is_null= 0; + my_bind[1].length= &bl2; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0); /* No-op at this point */ + check_execute_r(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 0: %d, %s", bc1, bc2); + + c2[0]= '\0'; l2= 0; + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)c2; + my_bind[0].buffer_length= 7; + my_bind[0].is_null= 0; + my_bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 1: %s(%ld)", c2, l2); + DIE_UNLESS(strncmp(c2, "venu", 4) == 0 && l2 == 4); + + c2[0]= '\0'; l2= 0; + rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 1: %s(%ld)", c2, l2); + DIE_UNLESS(strcmp(c2, "venu") == 0 && l2 == 4); + + c1= 0; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&c1; + my_bind[0].buffer_length= 0; + my_bind[0].is_null= 0; + my_bind[0].length= &l1; + + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 0: %d(%ld)", c1, l1); + DIE_UNLESS(c1 == 1 && l1 == 4); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n row 1: %d, %s", bc1, bc2); + + c2[0]= '\0'; l2= 0; + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)c2; + my_bind[0].buffer_length= 7; + my_bind[0].is_null= 0; + my_bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 1: %s(%ld)", c2, l2); + DIE_UNLESS(strncmp(c2, "mysq", 4) == 0 && l2 == 5); + + c2[0]= '\0'; l2= 0; + rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 1: %si(%ld)", c2, l2); + DIE_UNLESS(strcmp(c2, "mysql") == 0 && l2 == 5); + + c1= 0; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&c1; + my_bind[0].buffer_length= 0; + my_bind[0].is_null= 0; + my_bind[0].length= &l1; + + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 0: %d(%ld)", c1, l1); + DIE_UNLESS(c1 == 2 && l1 == 4); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0); + check_execute_r(stmt, rc); + + mysql_stmt_close(stmt); + myquery(mysql_query(mysql, "drop table t1")); +} + + +/* Test mysql_list_fields() */ + +static void test_list_fields() +{ + MYSQL_RES *result; + int rc; + myheader("test_list_fields"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1(c1 int primary key auto_increment, c2 char(10) default 'mysql')"); + myquery(rc); + + result= mysql_list_fields(mysql, "t1", NULL); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 0); + + verify_prepare_field(result, 0, "c1", "c1", MYSQL_TYPE_LONG, + "t1", "t1", + current_db, 11, "0"); + + verify_prepare_field(result, 1, "c2", "c2", MYSQL_TYPE_STRING, + "t1", "t1", + current_db, 10, "mysql"); + + mysql_free_result(result); + myquery(mysql_query(mysql, "drop table t1")); +} + + +/* Test mysql_list_fields() with information_schema */ + +static void test_list_information_schema_fields() +{ + MYSQL_RES *result; + int rc; + myheader("test_list_information_schema_fields"); + + rc= mysql_select_db(mysql, "information_schema"); + myquery(rc); + result= mysql_list_fields(mysql, "all_plugins", NULL); + mytest(result); + rc= my_process_result_set(result); + DIE_UNLESS(rc == 0); + mysql_free_result(result); + rc= mysql_select_db(mysql, current_db); + myquery(rc); +} + + +static void test_list_fields_blob() +{ + MYSQL_RES *result; + int rc; + myheader("test_list_fields_blob"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1(c1 tinyblob, c2 blob, c3 mediumblob, c4 longblob)"); + myquery(rc); + + result= mysql_list_fields(mysql, "t1", NULL); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 0); + + /* + All BLOB variant Fields are displayed as MYSQL_TYPE_BLOB in + the result set metadata. Note, some Items display the exact + BLOB type. This inconsistency should be fixed eventually. + */ + verify_prepare_field(result, 0, "c1", "c1", MYSQL_TYPE_BLOB, + "t1", "t1", + current_db, 255, NULL); + + verify_prepare_field(result, 1, "c2", "c2", MYSQL_TYPE_BLOB, + "t1", "t1", + current_db, 65535, NULL); + + verify_prepare_field(result, 2, "c3", "c3", MYSQL_TYPE_BLOB, + "t1", "t1", + current_db, 16777215, NULL); + + verify_prepare_field(result, 3, "c4", "c4", MYSQL_TYPE_BLOB, + "t1", "t1", + current_db, 4294967295ULL, NULL); + + mysql_free_result(result); + myquery(mysql_query(mysql, "drop table t1")); +} + + +static void test_list_fields_default() +{ + int rc, i; + myheader("test_list_fields_default"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, + "CREATE TABLE t1 (" + " i1 INT NOT NULL DEFAULT 0," + " i3 BIGINT UNSIGNED NOT NULL DEFAULT 0xFFFFFFFFFFFFFFFF," + " s1 VARCHAR(10) CHARACTER SET latin1 NOT NULL DEFAULT 's1def'," + " d1 DECIMAL(31,1) NOT NULL DEFAULT 111111111122222222223333333333.9," + " t1 DATETIME(6) NOT NULL DEFAULT '2001-01-01 10:20:30.123456'," + " e1 ENUM('a','b') NOT NULL DEFAULT 'a'" + ")"); + myquery(rc); + + rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE VIEW v1 AS SELECT * FROM t1"); + myquery(rc); + + /* + Checking that mysql_list_fields() returns the same result + for a TABLE and a VIEW on the same table. + */ + for (i= 0; i < 2; i++) + { + const char *table_name= i == 0 ? "t1" : "v1"; + MYSQL_RES *result= mysql_list_fields(mysql, table_name, NULL); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 0); + + verify_prepare_field(result, 0, "i1", "i1", MYSQL_TYPE_LONG, + table_name, table_name, current_db, + 11, "0"); + + verify_prepare_field(result, 1, "i3", "i3", MYSQL_TYPE_LONGLONG, + table_name, table_name, current_db, + 20, "18446744073709551615"); + + verify_prepare_field(result, 2, "s1", "s1", MYSQL_TYPE_VAR_STRING, + table_name, table_name, current_db, + 10, "s1def"); + + verify_prepare_field(result, 3, "d1", "d1", MYSQL_TYPE_NEWDECIMAL, + table_name, table_name, current_db, + 33, "111111111122222222223333333333.9"); + + verify_prepare_field(result, 4, "t1", "t1", MYSQL_TYPE_DATETIME, + table_name, table_name, current_db, + 26, "2001-01-01 10:20:30.123456"); + + verify_prepare_field(result, 5, "e1", "e1", MYSQL_TYPE_STRING, + table_name, table_name, current_db, + 1, "a"); + + mysql_free_result(result); + } + + myquery(mysql_query(mysql, "DROP VIEW v1")); + myquery(mysql_query(mysql, "DROP TABLE t1")); +} + + +/** + Note, this test covers MDEV-18408 and MDEV-18685 +*/ + +static void test_mdev18408() +{ + MYSQL_RES *result; + int rc; + myheader("test_mdev18408s"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (c1 TIMESTAMP NULL DEFAULT NULL)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE VIEW v1 AS SELECT c1 FROM t1"); + myquery(rc); + + result= mysql_list_fields(mysql, "v1", NULL); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 0); + + verify_prepare_field(result, 0, "c1", "c1", MYSQL_TYPE_TIMESTAMP, + "v1", "v1", current_db, 19, 0); + + mysql_free_result(result); + myquery(mysql_query(mysql, "DROP VIEW v1")); + myquery(mysql_query(mysql, "DROP TABLE t1")); +} + + +static void test_bug19671() +{ + MYSQL_RES *result; + int rc; + myheader("test_bug19671"); + + mysql_query(mysql, "set sql_mode=''"); + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + rc= mysql_query(mysql, "drop view if exists v1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1(f1 int)"); + myquery(rc); + + rc= mysql_query(mysql, "create view v1 as select va.* from t1 va"); + myquery(rc); + + result= mysql_list_fields(mysql, "v1", NULL); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 0); + + verify_prepare_field(result, 0, "f1", "f1", MYSQL_TYPE_LONG, + "v1", "v1", current_db, 11, NULL); + + mysql_free_result(result); + myquery(mysql_query(mysql, "drop view v1")); + myquery(mysql_query(mysql, "drop table t1")); +} + + +/* Test a memory ovverun bug */ + +static void test_mem_overun() +{ + char buffer[10000], field[10]; + MYSQL_STMT *stmt; + MYSQL_RES *field_res; + int rc, length; + unsigned i; + + myheader("test_mem_overun"); + + /* + Test a memory ovverun bug when a table had 1000 fields with + a row of data + */ + rc= mysql_query(mysql, "drop table if exists t_mem_overun"); + myquery(rc); + + strxmov(buffer, "create table t_mem_overun(", NullS); + for (i= 0; i < 1000; i++) + { + sprintf(field, "c%u int", i); + strxmov(buffer, buffer, field, ", ", NullS); + } + length= strlen(buffer); + buffer[length-2]= ')'; + buffer[--length]= '\0'; + + rc= mysql_real_query(mysql, buffer, length); + myquery(rc); + + strxmov(buffer, "insert into t_mem_overun values(", NullS); + for (i= 0; i < 1000; i++) + { + strxmov(buffer, buffer, "1, ", NullS); + } + length= strlen(buffer); + buffer[length-2]= ')'; + buffer[--length]= '\0'; + + rc= mysql_real_query(mysql, buffer, length); + myquery(rc); + + rc= mysql_query(mysql, "select * from t_mem_overun"); + myquery(rc); + + rc= my_process_result(mysql); + DIE_UNLESS(rc == 1); + + stmt= mysql_simple_prepare(mysql, "select * from t_mem_overun"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + field_res= mysql_stmt_result_metadata(stmt); + mytest(field_res); + + if (!opt_silent) + fprintf(stdout, "\n total fields : %d", mysql_num_fields(field_res)); + DIE_UNLESS( 1000 == mysql_num_fields(field_res)); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_free_result(field_res); + + mysql_stmt_close(stmt); +} + + +/* Test mysql_stmt_free_result() */ + +static void test_free_result() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + char c2[5]; + ulong bl1, l2; + int rc, c1, bc1; + + myheader("test_free_result"); + + rc= mysql_query(mysql, "drop table if exists test_free_result"); + myquery(rc); + + rc= mysql_query(mysql, "create table test_free_result(" + "c1 int primary key auto_increment)"); + myquery(rc); + + rc= mysql_query(mysql, "insert into test_free_result values(), (), ()"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "select * from test_free_result"); + check_stmt(stmt); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&bc1; + my_bind[0].length= &bl1; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + c2[0]= '\0'; l2= 0; + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)c2; + my_bind[0].buffer_length= 7; + my_bind[0].is_null= 0; + my_bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 0: %s(%ld)", c2, l2); + DIE_UNLESS(strncmp(c2, "1", 1) == 0 && l2 == 1); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + c1= 0, l2= 0; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&c1; + my_bind[0].buffer_length= 0; + my_bind[0].is_null= 0; + my_bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 0: %d(%ld)", c1, l2); + DIE_UNLESS(c1 == 2 && l2 == 4); + + rc= mysql_query(mysql, "drop table test_free_result"); + myquery_r(rc); /* error should be, COMMANDS OUT OF SYNC */ + + rc= mysql_stmt_free_result(stmt); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "drop table test_free_result"); + myquery(rc); /* should be successful */ + + mysql_stmt_close(stmt); +} + + +/* Test mysql_stmt_store_result() */ + +static void test_free_store_result() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + char c2[5]; + ulong bl1, l2; + int rc, c1, bc1; + + myheader("test_free_store_result"); + + rc= mysql_query(mysql, "drop table if exists test_free_result"); + myquery(rc); + + rc= mysql_query(mysql, "create table test_free_result(c1 int primary key auto_increment)"); + myquery(rc); + + rc= mysql_query(mysql, "insert into test_free_result values(), (), ()"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "select * from test_free_result"); + check_stmt(stmt); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&bc1; + my_bind[0].buffer_length= 0; + my_bind[0].is_null= 0; + my_bind[0].length= &bl1; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + c2[0]= '\0'; l2= 0; + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)c2; + my_bind[0].buffer_length= 7; + my_bind[0].is_null= 0; + my_bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 1: %s(%ld)", c2, l2); + DIE_UNLESS(strncmp(c2, "1", 1) == 0 && l2 == 1); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + c1= 0, l2= 0; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&c1; + my_bind[0].buffer_length= 0; + my_bind[0].is_null= 0; + my_bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n col 0: %d(%ld)", c1, l2); + DIE_UNLESS(c1 == 2 && l2 == 4); + + rc= mysql_stmt_free_result(stmt); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "drop table test_free_result"); + myquery(rc); + + mysql_stmt_close(stmt); +} + + +/* Test SQLmode */ + +static void test_sqlmode() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + char c1[5], c2[5]; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_sqlmode"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_piping"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_piping(name varchar(10))"); + myquery(rc); + + /* PIPES_AS_CONCAT */ + strmov(query, "SET SQL_MODE= \"PIPES_AS_CONCAT\""); + if (!opt_silent) + fprintf(stdout, "\n With %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + strmov(query, "INSERT INTO test_piping VALUES(?||?)"); + if (!opt_silent) + fprintf(stdout, "\n query: %s", query); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + if (!opt_silent) + fprintf(stdout, "\n total parameters: %ld", mysql_stmt_param_count(stmt)); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)c1; + my_bind[0].buffer_length= 2; + + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void *)c2; + my_bind[1].buffer_length= 3; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + strmov(c1, "My"); strmov(c2, "SQL"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_close(stmt); + + verify_col_data("test_piping", "name", "MySQL"); + + rc= mysql_query(mysql, "DELETE FROM test_piping"); + myquery(rc); + + strmov(query, "SELECT connection_id ()"); + if (!opt_silent) + fprintf(stdout, "\n query: %s", query); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + mysql_stmt_close(stmt); + + /* ANSI */ + strmov(query, "SET SQL_MODE= \"ANSI\""); + if (!opt_silent) + fprintf(stdout, "\n With %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + strmov(query, "INSERT INTO test_piping VALUES(?||?)"); + if (!opt_silent) + fprintf(stdout, "\n query: %s", query); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + if (!opt_silent) + fprintf(stdout, "\n total parameters: %ld", mysql_stmt_param_count(stmt)); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + strmov(c1, "My"); strmov(c2, "SQL"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + verify_col_data("test_piping", "name", "MySQL"); + + /* ANSI mode spaces ... */ + strmov(query, "SELECT connection_id ()"); + if (!opt_silent) + fprintf(stdout, "\n query: %s", query); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + if (!opt_silent) + fprintf(stdout, "\n returned 1 row\n"); + + mysql_stmt_close(stmt); + + /* IGNORE SPACE MODE */ + strmov(query, "SET SQL_MODE= \"IGNORE_SPACE\""); + if (!opt_silent) + fprintf(stdout, "\n With %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + strmov(query, "SELECT connection_id ()"); + if (!opt_silent) + fprintf(stdout, "\n query: %s", query); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + if (!opt_silent) + fprintf(stdout, "\n returned 1 row"); + + mysql_stmt_close(stmt); +} + + +/* Test for timestamp handling */ + +static void test_ts() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[6]; + MYSQL_TIME ts; + MYSQL_RES *prep_res; + char strts[30]; + ulong length; + int rc, field_count; + char name; + char query[MAX_TEST_QUERY_LENGTH]; + const char *queries [3]= {"SELECT a, b, c FROM test_ts WHERE %c=?", + "SELECT a, b, c FROM test_ts WHERE %c=CAST(? AS TIME)", + "SELECT a, b, c FROM test_ts WHERE %c=CAST(? AS DATE)"}; + myheader("test_ts"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ts"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_ts(a DATE, b TIME, c TIMESTAMP)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "INSERT INTO test_ts VALUES(?, ?, ?), (?, ?, ?)"); + check_stmt(stmt); + + ts.year= 2003; + ts.month= 07; + ts.day= 12; + ts.hour= 21; + ts.minute= 07; + ts.second= 46; + ts.second_part= 0; + length= (long)(strmov(strts, "2003-07-12 21:07:46") - strts); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_TIMESTAMP; + my_bind[0].buffer= (void *)&ts; + my_bind[0].buffer_length= sizeof(ts); + + my_bind[2]= my_bind[1]= my_bind[0]; + + my_bind[3].buffer_type= MYSQL_TYPE_STRING; + my_bind[3].buffer= (void *)strts; + my_bind[3].buffer_length= sizeof(strts); + my_bind[3].length= &length; + + my_bind[5]= my_bind[4]= my_bind[3]; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + verify_col_data("test_ts", "a", "2003-07-12"); + verify_col_data("test_ts", "b", "21:07:46"); + verify_col_data("test_ts", "c", "2003-07-12 21:07:46"); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM test_ts"); + check_stmt(stmt); + + prep_res= mysql_stmt_result_metadata(stmt); + mytest(prep_res); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 2); + field_count= mysql_num_fields(prep_res); + + mysql_free_result(prep_res); + mysql_stmt_close(stmt); + + for (name= 'a'; field_count--; name++) + { + int row_count= 0; + + sprintf(query, queries[field_count], name); + + if (!opt_silent) + fprintf(stdout, "\n %s", query); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + while (mysql_stmt_fetch(stmt) == 0) + row_count++; + + if (!opt_silent) + fprintf(stdout, "\n returned '%d' rows", row_count); + DIE_UNLESS(row_count == 2); + mysql_stmt_close(stmt); + } +} + + +/* Test for bug #1500. */ + +static void test_bug1500() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[3]; + int rc; + int32 int_data[3]= {2, 3, 4}; + const char *data; + + myheader("test_bug1500"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bg1500"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bg1500 (i INT)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO test_bg1500 VALUES (1), (2)"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "SELECT i FROM test_bg1500 WHERE i IN (?, ?, ?)"); + check_stmt(stmt); + verify_param_count(stmt, 3); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer= (void *)int_data; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[2]= my_bind[1]= my_bind[0]; + my_bind[1].buffer= (void *)(int_data + 1); + my_bind[2].buffer= (void *)(int_data + 2); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE test_bg1500"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bg1500 (s VARCHAR(25), FULLTEXT(s)) engine=MyISAM"); + myquery(rc); + + rc= mysql_query(mysql, + "INSERT INTO test_bg1500 VALUES ('Gravedigger'), ('Greed'), ('Hollow Dogs')"); + myquery(rc); + + rc= mysql_commit(mysql); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, + "SELECT s FROM test_bg1500 WHERE MATCH (s) AGAINST (?)"); + check_stmt(stmt); + + verify_param_count(stmt, 1); + + data= "Dogs"; + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *) data; + my_bind[0].buffer_length= strlen(data); + my_bind[0].is_null= 0; + my_bind[0].length= 0; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); + + /* This should work too */ + stmt= mysql_simple_prepare(mysql, + "SELECT s FROM test_bg1500 WHERE MATCH (s) AGAINST (CONCAT(?, 'digger'))"); + check_stmt(stmt); + + verify_param_count(stmt, 1); + + data= "Grave"; + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *) data; + my_bind[0].buffer_length= strlen(data); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); +} + + +static void test_bug1946() +{ + MYSQL_STMT *stmt; + int rc; + const char *query= "INSERT INTO prepare_command VALUES (?)"; + + myheader("test_bug1946"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS prepare_command"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE prepare_command(ID INT)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + rc= mysql_real_query(mysql, query, strlen(query)); + DIE_UNLESS(rc != 0); + if (!opt_silent) + fprintf(stdout, "Got error (as expected):\n"); + myerror(NULL); + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "DROP TABLE prepare_command"); +} + + +static void test_parse_error_and_bad_length() +{ + MYSQL_STMT *stmt; + int rc; + + /* check that we get 4 syntax errors over the 4 calls */ + myheader("test_parse_error_and_bad_length"); + + rc= mysql_query(mysql, "SHOW DATABAAAA"); + DIE_UNLESS(rc); + if (!opt_silent) + fprintf(stdout, "Got error (as expected): '%s'\n", mysql_error(mysql)); + rc= mysql_real_query(mysql, STRING_WITH_LEN("SHOW DATABASES\0AAAAAAAA")); + DIE_UNLESS(rc); + if (!opt_silent) + fprintf(stdout, "Got error (as expected): '%s'\n", mysql_error(mysql)); + + stmt= mysql_simple_prepare(mysql, "SHOW DATABAAAA"); + DIE_UNLESS(!stmt); + if (!opt_silent) + fprintf(stdout, "Got error (as expected): '%s'\n", mysql_error(mysql)); + stmt= mysql_stmt_init(mysql); + DIE_UNLESS(stmt); + rc= mysql_stmt_prepare(stmt, STRING_WITH_LEN("SHOW DATABASES\0AAAAAAA")); + DIE_UNLESS(rc != 0); + if (!opt_silent) + fprintf(stdout, "Got error (as expected): '%s'\n", mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); +} + + +static void test_bug2247() +{ + MYSQL_STMT *stmt; + MYSQL_RES *res; + int rc; + int i; + const char *create= "CREATE TABLE bug2247(id INT UNIQUE AUTO_INCREMENT)"; + const char *insert= "INSERT INTO bug2247 VALUES (NULL)"; + const char *SELECT= "SELECT id FROM bug2247"; + const char *update= "UPDATE bug2247 SET id=id+10"; + const char *drop= "DROP TABLE IF EXISTS bug2247"; + ulonglong exp_count; + enum { NUM_ROWS= 5 }; + + myheader("test_bug2247"); + + if (!opt_silent) + fprintf(stdout, "\nChecking if stmt_affected_rows is not affected by\n" + "mysql_query ... "); + /* create table and insert few rows */ + rc= mysql_query(mysql, drop); + myquery(rc); + + rc= mysql_query(mysql, create); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, insert); + check_stmt(stmt); + for (i= 0; i < NUM_ROWS; ++i) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + exp_count= mysql_stmt_affected_rows(stmt); + DIE_UNLESS(exp_count == 1); + + rc= mysql_query(mysql, SELECT); + myquery(rc); + /* + mysql_store_result overwrites mysql->affected_rows. Check that + mysql_stmt_affected_rows() returns the same value, whereas + mysql_affected_rows() value is correct. + */ + res= mysql_store_result(mysql); + mytest(res); + + DIE_UNLESS(mysql_affected_rows(mysql) == NUM_ROWS); + DIE_UNLESS(exp_count == mysql_stmt_affected_rows(stmt)); + + rc= mysql_query(mysql, update); + myquery(rc); + DIE_UNLESS(mysql_affected_rows(mysql) == NUM_ROWS); + DIE_UNLESS(exp_count == mysql_stmt_affected_rows(stmt)); + + mysql_free_result(res); + mysql_stmt_close(stmt); + + /* check that mysql_stmt_store_result modifies mysql_stmt_affected_rows */ + stmt= mysql_simple_prepare(mysql, SELECT); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + exp_count= mysql_stmt_affected_rows(stmt); + DIE_UNLESS(exp_count == NUM_ROWS); + + rc= mysql_query(mysql, insert); + myquery(rc); + DIE_UNLESS(mysql_affected_rows(mysql) == 1); + DIE_UNLESS(mysql_stmt_affected_rows(stmt) == exp_count); + + mysql_stmt_close(stmt); + if (!opt_silent) + fprintf(stdout, "OK"); +} + + +static void test_subqueries() +{ + MYSQL_STMT *stmt; + int rc, i; + const char *query= "SELECT (SELECT SUM(a+b) FROM t2 where t1.b=t2.b GROUP BY t1.a LIMIT 1) as scalar_s, exists (select 1 from t2 where t2.a/2=t1.a) as exists_s, a in (select a+3 from t2) as in_s, (a-1, b-1) in (select a, b from t2) as in_row_s FROM t1, (select a x, b y from t2) tt WHERE x=a"; + + myheader("test_subqueries"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a int , b int);"); + myquery(rc); + + rc= mysql_query(mysql, + "insert into t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);"); + myquery(rc); + + rc= mysql_query(mysql, "create table t2 select * from t1;"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 5); + } + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + myquery(rc); +} + + +static void test_bad_union() +{ + MYSQL_STMT *stmt; + const char *query= "SELECT 1, 2 union SELECT 1"; + + myheader("test_bad_union"); + + stmt= mysql_simple_prepare(mysql, query); + DIE_UNLESS(stmt == 0); + myerror(NULL); +} + + +static void test_distinct() +{ + MYSQL_STMT *stmt; + int rc, i; + const char *query= + "SELECT 2+count(distinct b), group_concat(a) FROM t1 group by a"; + + myheader("test_distinct"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a int , b int);"); + myquery(rc); + + rc= mysql_query(mysql, + "insert into t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), \ +(1, 10), (2, 20), (3, 30), (4, 40), (5, 50);"); + myquery(rc); + + for (i= 0; i < 3; i++) + { + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 5); + mysql_stmt_close(stmt); + } + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + + +/* + Test for bug#2248 "mysql_fetch without prior mysql_stmt_execute hangs" +*/ + +static void test_bug2248() +{ + MYSQL_STMT *stmt; + int rc; + const char *query1= "SELECT DATABASE()"; + const char *query2= "INSERT INTO test_bug2248 VALUES (10)"; + + myheader("test_bug2248"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bug2248"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_bug2248 (id int)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, query1); + check_stmt(stmt); + + /* This should not hang */ + rc= mysql_stmt_fetch(stmt); + check_execute_r(stmt, rc); + + /* And this too */ + rc= mysql_stmt_store_result(stmt); + check_execute_r(stmt, rc); + + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, query2); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* This too should not hang but should return proper error */ + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 1); + + /* This too should not hang but should not bark */ + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + /* This should return proper error */ + rc= mysql_stmt_fetch(stmt); + check_execute_r(stmt, rc); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE test_bug2248"); + myquery(rc); +} + + +static void test_subqueries_ref() +{ + MYSQL_STMT *stmt; + int rc, i; + const char *query= "SELECT a as ccc from t1 outr where a+1=(SELECT 1+outr.a from t1 where outr.a+1=a+1 and a=1)"; + + myheader("test_subqueries_ref"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a int);"); + myquery(rc); + + rc= mysql_query(mysql, + "insert into t1 values (1), (2), (3), (4), (5);"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + } + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + + +static void test_union() +{ + MYSQL_STMT *stmt; + int rc; + + myheader("test_union"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2"); + myquery(rc); + + rc= mysql_query(mysql, + "CREATE TABLE t1 " + "(id INTEGER NOT NULL PRIMARY KEY, " + " name VARCHAR(20) NOT NULL)"); + myquery(rc); + rc= mysql_query(mysql, + "INSERT INTO t1 (id, name) VALUES " + "(2, 'Ja'), (3, 'Ede'), " + "(4, 'Haag'), (5, 'Kabul'), " + "(6, 'Almere'), (7, 'Utrecht'), " + "(8, 'Qandahar'), (9, 'Amsterdam'), " + "(10, 'Amersfoort'), (11, 'Constantine')"); + myquery(rc); + rc= mysql_query(mysql, + "CREATE TABLE t2 " + "(id INTEGER NOT NULL PRIMARY KEY, " + " name VARCHAR(20) NOT NULL)"); + myquery(rc); + rc= mysql_query(mysql, + "INSERT INTO t2 (id, name) VALUES " + "(4, 'Guam'), (5, 'Aruba'), " + "(6, 'Angola'), (7, 'Albania'), " + "(8, 'Anguilla'), (9, 'Argentina'), " + "(10, 'Azerbaijan'), (11, 'Afghanistan'), " + "(12, 'Burkina Faso'), (13, 'Faroe Islands')"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, + "SELECT t1.name FROM t1 UNION " + "SELECT t2.name FROM t2"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 20); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + myquery(rc); +} + + +static void test_bug3117() +{ + MYSQL_STMT *stmt; + MYSQL_BIND buffer; + longlong lii; + ulong length; + my_bool is_null; + int rc; + + myheader("test_bug3117"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (id int auto_increment primary key)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "SELECT LAST_INSERT_ID()"); + check_stmt(stmt); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (NULL)"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero((char*) &buffer, sizeof(buffer)); + buffer.buffer_type= MYSQL_TYPE_LONGLONG; + buffer.buffer_length= sizeof(lii); + buffer.buffer= (void *)&lii; + buffer.length= &length; + buffer.is_null= &is_null; + + rc= mysql_stmt_bind_result(stmt, &buffer); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(is_null == 0 && lii == 1); + if (!opt_silent) + fprintf(stdout, "\n\tLAST_INSERT_ID()= 1 ok\n"); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (NULL)"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(is_null == 0 && lii == 2); + if (!opt_silent) + fprintf(stdout, "\tLAST_INSERT_ID()= 2 ok\n"); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + + +static void test_join() +{ + MYSQL_STMT *stmt; + int rc, i, j; + const char *query[]= {"SELECT * FROM t2 join t1 on (t1.a=t2.a)", + "SELECT * FROM t2 natural join t1", + "SELECT * FROM t2 join t1 using(a)", + "SELECT * FROM t2 left join t1 on(t1.a=t2.a)", + "SELECT * FROM t2 natural left join t1", + "SELECT * FROM t2 left join t1 using(a)", + "SELECT * FROM t2 right join t1 on(t1.a=t2.a)", + "SELECT * FROM t2 natural right join t1", + "SELECT * FROM t2 right join t1 using(a)"}; + + myheader("test_join"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a int , b int);"); + myquery(rc); + + rc= mysql_query(mysql, + "insert into t1 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2 (a int , c int);"); + myquery(rc); + + rc= mysql_query(mysql, + "insert into t2 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);"); + myquery(rc); + + for (j= 0; j < 9; j++) + { + stmt= mysql_simple_prepare(mysql, query[j]); + check_stmt(stmt); + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 5); + } + mysql_stmt_close(stmt); + } + + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + myquery(rc); +} + + +static void test_selecttmp() +{ + MYSQL_STMT *stmt; + int rc, i; + const char *query= "select a, (select count(distinct t1.b) as sum from t1, t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) from t3"; + + myheader("test_select_tmp"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2, t3"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a int , b int);"); + myquery(rc); + + rc= mysql_query(mysql, "create table t2 (a int, b int);"); + myquery(rc); + + rc= mysql_query(mysql, "create table t3 (a int, b int);"); + myquery(rc); + + rc= mysql_query(mysql, + "insert into t1 values (0, 100), (1, 2), (1, 3), (2, 2), (2, 7), \ +(2, -1), (3, 10);"); + myquery(rc); + rc= mysql_query(mysql, + "insert into t2 values (0, 0), (1, 1), (2, 1), (3, 1), (4, 1);"); + myquery(rc); + rc= mysql_query(mysql, + "insert into t3 values (3, 3), (2, 2), (1, 1);"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 3); + } + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1, t2, t3"); + myquery(rc); +} + + +static void test_create_drop() +{ + MYSQL_STMT *stmt_create, *stmt_drop, *stmt_select, *stmt_create_select; + char *query; + int rc, i; + myheader("test_table_manipulation"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2"); + myquery(rc); + + rc= mysql_query(mysql, "create table t2 (a int);"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 (a int);"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t2 values (3), (2), (1);"); + myquery(rc); + + query= (char*)"create table t1 (a int)"; + stmt_create= mysql_simple_prepare(mysql, query); + check_stmt(stmt_create); + + query= (char*)"drop table t1"; + stmt_drop= mysql_simple_prepare(mysql, query); + check_stmt(stmt_drop); + + query= (char*)"select a in (select a from t2) from t1"; + stmt_select= mysql_simple_prepare(mysql, query); + check_stmt(stmt_select); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + query= (char*)"create table t1 select a from t2"; + stmt_create_select= mysql_simple_prepare(mysql, query); + check_stmt(stmt_create_select); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt_create); + check_execute(stmt_create, rc); + if (!opt_silent) + fprintf(stdout, "created %i\n", i); + + rc= mysql_stmt_execute(stmt_select); + check_execute(stmt_select, rc); + rc= my_process_stmt_result(stmt_select); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt_drop); + check_execute(stmt_drop, rc); + if (!opt_silent) + fprintf(stdout, "dropped %i\n", i); + + rc= mysql_stmt_execute(stmt_create_select); + check_execute(stmt_create, rc); + if (!opt_silent) + fprintf(stdout, "created select %i\n", i); + + rc= mysql_stmt_execute(stmt_select); + check_execute(stmt_select, rc); + rc= my_process_stmt_result(stmt_select); + DIE_UNLESS(rc == 3); + + rc= mysql_stmt_execute(stmt_drop); + check_execute(stmt_drop, rc); + if (!opt_silent) + fprintf(stdout, "dropped %i\n", i); + } + + mysql_stmt_close(stmt_create); + mysql_stmt_close(stmt_drop); + mysql_stmt_close(stmt_select); + mysql_stmt_close(stmt_create_select); + + rc= mysql_query(mysql, "DROP TABLE t2"); + myquery(rc); +} + + +static void test_rename() +{ + MYSQL_STMT *stmt; + const char *query= "rename table t1 to t2, t3 to t4"; + int rc; + myheader("test_table_rename"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2, t3, t4"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_query(mysql, "create table t1 (a int)"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute_r(stmt, rc); + if (!opt_silent) + fprintf(stdout, "rename without t3\n"); + + rc= mysql_query(mysql, "create table t3 (a int)"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "rename with t3\n"); + + rc= mysql_stmt_execute(stmt); + check_execute_r(stmt, rc); + if (!opt_silent) + fprintf(stdout, "rename renamed\n"); + + rc= mysql_query(mysql, "rename table t2 to t1, t4 to t3"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "rename reverted\n"); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t2, t4"); + myquery(rc); +} + + +static void test_do_set() +{ + MYSQL_STMT *stmt_do, *stmt_set; + char *query; + int rc, i; + myheader("test_do_set"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 (a int)"); + myquery(rc); + + query= (char*)"do @var:=(1 in (select * from t1))"; + stmt_do= mysql_simple_prepare(mysql, query); + check_stmt(stmt_do); + + query= (char*)"set @var=(1 in (select * from t1))"; + stmt_set= mysql_simple_prepare(mysql, query); + check_stmt(stmt_set); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt_do); + check_execute(stmt_do, rc); + if (!opt_silent) + fprintf(stdout, "do %i\n", i); + rc= mysql_stmt_execute(stmt_set); + check_execute(stmt_set, rc); + if (!opt_silent) + fprintf(stdout, "set %i\n", i); + } + + mysql_stmt_close(stmt_do); + mysql_stmt_close(stmt_set); +} + + +static void test_multi() +{ + MYSQL_STMT *stmt_delete, *stmt_update, *stmt_select1, *stmt_select2; + char *query; + MYSQL_BIND my_bind[1]; + int rc, i; + int32 param= 1; + ulong length= 1; + myheader("test_multi"); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)¶m; + my_bind[0].length= &length; + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 (a int, b int)"); + myquery(rc); + + rc= mysql_query(mysql, "create table t2 (a int, b int)"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1 values (3, 3), (2, 2), (1, 1)"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t2 values (3, 3), (2, 2), (1, 1)"); + myquery(rc); + + query= (char*)"delete t1, t2 from t1, t2 where t1.a=t2.a and t1.b=10"; + stmt_delete= mysql_simple_prepare(mysql, query); + check_stmt(stmt_delete); + + query= (char*)"update t1, t2 set t1.b=10, t2.b=10 where t1.a=t2.a and t1.b=?"; + stmt_update= mysql_simple_prepare(mysql, query); + check_stmt(stmt_update); + + query= (char*)"select * from t1"; + stmt_select1= mysql_simple_prepare(mysql, query); + check_stmt(stmt_select1); + + query= (char*)"select * from t2"; + stmt_select2= mysql_simple_prepare(mysql, query); + check_stmt(stmt_select2); + + for(i= 0; i < 3; i++) + { + rc= mysql_stmt_bind_param(stmt_update, my_bind); + check_execute(stmt_update, rc); + + rc= mysql_stmt_execute(stmt_update); + check_execute(stmt_update, rc); + if (!opt_silent) + fprintf(stdout, "update %ld\n", (long) param); + + rc= mysql_stmt_execute(stmt_delete); + check_execute(stmt_delete, rc); + if (!opt_silent) + fprintf(stdout, "delete %ld\n", (long) param); + + rc= mysql_stmt_execute(stmt_select1); + check_execute(stmt_select1, rc); + rc= my_process_stmt_result(stmt_select1); + DIE_UNLESS(rc == 3-param); + + rc= mysql_stmt_execute(stmt_select2); + check_execute(stmt_select2, rc); + rc= my_process_stmt_result(stmt_select2); + DIE_UNLESS(rc == 3-param); + + param++; + } + + mysql_stmt_close(stmt_delete); + mysql_stmt_close(stmt_update); + mysql_stmt_close(stmt_select1); + mysql_stmt_close(stmt_select2); + rc= mysql_query(mysql, "drop table t1, t2"); + myquery(rc); +} + + +static void test_insert_select() +{ + MYSQL_STMT *stmt_insert, *stmt_select; + char *query; + int rc; + uint i; + myheader("test_insert_select"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 (a int)"); + myquery(rc); + + rc= mysql_query(mysql, "create table t2 (a int)"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t2 values (1)"); + myquery(rc); + + query= (char*)"insert into t1 select a from t2"; + stmt_insert= mysql_simple_prepare(mysql, query); + check_stmt(stmt_insert); + + query= (char*)"select * from t1"; + stmt_select= mysql_simple_prepare(mysql, query); + check_stmt(stmt_select); + + for(i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt_insert); + check_execute(stmt_insert, rc); + if (!opt_silent) + fprintf(stdout, "insert %u\n", i); + + rc= mysql_stmt_execute(stmt_select); + check_execute(stmt_select, rc); + rc= my_process_stmt_result(stmt_select); + DIE_UNLESS(rc == (int)(i+1)); + } + + mysql_stmt_close(stmt_insert); + mysql_stmt_close(stmt_select); + rc= mysql_query(mysql, "drop table t1, t2"); + myquery(rc); +} + + +static void test_bind_nagative() +{ + MYSQL_STMT *stmt_insert; + char *query; + int rc; + MYSQL_BIND my_bind[1]; + int32 my_val= 0; + ulong my_length= 0L; + my_bool my_null= FALSE; + myheader("test_insert_select"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "create temporary table t1 (c1 int unsigned)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1), (-1)"); + myquery(rc); + + query= (char*)"INSERT INTO t1 VALUES (?)"; + stmt_insert= mysql_simple_prepare(mysql, query); + check_stmt(stmt_insert); + + /* bind parameters */ + bzero((char*) my_bind, sizeof(my_bind)); + + 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; + + rc= mysql_stmt_bind_param(stmt_insert, my_bind); + check_execute(stmt_insert, rc); + + my_val= -1; + rc= mysql_stmt_execute(stmt_insert); + check_execute(stmt_insert, rc); + + mysql_stmt_close(stmt_insert); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +static void test_derived() +{ + MYSQL_STMT *stmt; + int rc, i; + MYSQL_BIND my_bind[1]; + int32 my_val= 0; + ulong my_length= 0L; + my_bool my_null= FALSE; + const char *query= + "select count(1) from (select f.id from t1 f where f.id=?) as x"; + + myheader("test_derived"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 (id int(8), primary key (id)) \ +ENGINE=InnoDB DEFAULT CHARSET=utf8"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1 values (1)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + 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_val= 1; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + } + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + + +static void test_xjoin() +{ + MYSQL_STMT *stmt; + int rc, i; + const char *query= + "select t.id, p1.value, n1.value, p2.value, n2.value from t3 t LEFT JOIN t1 p1 ON (p1.id=t.param1_id) LEFT JOIN t2 p2 ON (p2.id=t.param2_id) LEFT JOIN t4 n1 ON (n1.id=p1.name_id) LEFT JOIN t4 n2 ON (n2.id=p2.name_id) where t.id=1"; + + myheader("test_xjoin"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2, t3, t4"); + myquery(rc); + + rc= mysql_query(mysql, "create table t3 (id int(8), param1_id int(8), param2_id int(8)) ENGINE=InnoDB DEFAULT CHARSET=utf8"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 ( id int(8), name_id int(8), value varchar(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8"); + myquery(rc); + + rc= mysql_query(mysql, "create table t2 (id int(8), name_id int(8), value varchar(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + myquery(rc); + + rc= mysql_query(mysql, "create table t4(id int(8), value varchar(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t3 values (1, 1, 1), (2, 2, null)"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1 values (1, 1, 'aaa'), (2, null, 'bbb')"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t2 values (1, 2, 'ccc')"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t4 values (1, 'Name1'), (2, null)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + } + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1, t2, t3, t4"); + myquery(rc); +} + + +static void test_bug3035() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_BIND bind_array[12], *my_bind= bind_array, *bind_end= my_bind + 12; + int8 int8_val; + uint8 uint8_val; + int16 int16_val; + uint16 uint16_val; + int32 int32_val; + uint32 uint32_val; + longlong int64_val; + ulonglong uint64_val; + double double_val, udouble_val, double_tmp; + char longlong_as_string[22], ulonglong_as_string[22]; + + /* mins and maxes */ + const int8 int8_min= -128; + const int8 int8_max= 127; + const uint8 uint8_min= 0; + const uint8 uint8_max= 255; + + const int16 int16_min= -32768; + const int16 int16_max= 32767; + const uint16 uint16_min= 0; + const uint16 uint16_max= 65535; + + const int32 int32_max= 2147483647L; + const int32 int32_min= -int32_max - 1; + const uint32 uint32_min= 0; + const uint32 uint32_max= 4294967295U; + + /* it might not work okay everyplace */ + const longlong int64_max= 9223372036854775807LL; + const longlong int64_min= -int64_max - 1; + + const ulonglong uint64_min= 0U; + const ulonglong uint64_max= 18446744073709551615ULL; + + const char *stmt_text; + + myheader("test_bug3035"); + + stmt_text= "DROP TABLE IF EXISTS t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "CREATE TABLE t1 (i8 TINYINT, ui8 TINYINT UNSIGNED, " + "i16 SMALLINT, ui16 SMALLINT UNSIGNED, " + "i32 INT, ui32 INT UNSIGNED, " + "i64 BIGINT, ui64 BIGINT UNSIGNED, " + "id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + bzero((char*) bind_array, sizeof(bind_array)); + + for (my_bind= bind_array; my_bind < bind_end; my_bind++) + my_bind->error= &my_bind->error_value; + + bind_array[0].buffer_type= MYSQL_TYPE_TINY; + bind_array[0].buffer= (void *) &int8_val; + + bind_array[1].buffer_type= MYSQL_TYPE_TINY; + bind_array[1].buffer= (void *) &uint8_val; + bind_array[1].is_unsigned= 1; + + bind_array[2].buffer_type= MYSQL_TYPE_SHORT; + bind_array[2].buffer= (void *) &int16_val; + + bind_array[3].buffer_type= MYSQL_TYPE_SHORT; + bind_array[3].buffer= (void *) &uint16_val; + bind_array[3].is_unsigned= 1; + + bind_array[4].buffer_type= MYSQL_TYPE_LONG; + bind_array[4].buffer= (void *) &int32_val; + + bind_array[5].buffer_type= MYSQL_TYPE_LONG; + bind_array[5].buffer= (void *) &uint32_val; + bind_array[5].is_unsigned= 1; + + bind_array[6].buffer_type= MYSQL_TYPE_LONGLONG; + bind_array[6].buffer= (void *) &int64_val; + + bind_array[7].buffer_type= MYSQL_TYPE_LONGLONG; + bind_array[7].buffer= (void *) &uint64_val; + bind_array[7].is_unsigned= 1; + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + stmt_text= "INSERT INTO t1 (i8, ui8, i16, ui16, i32, ui32, i64, ui64) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + mysql_stmt_bind_param(stmt, bind_array); + + int8_val= int8_min; + uint8_val= uint8_min; + int16_val= int16_min; + uint16_val= uint16_min; + int32_val= int32_min; + uint32_val= uint32_min; + int64_val= int64_min; + uint64_val= uint64_min; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + int8_val= int8_max; + uint8_val= uint8_max; + int16_val= int16_max; + uint16_val= uint16_max; + int32_val= int32_max; + uint32_val= uint32_max; + int64_val= int64_max; + uint64_val= uint64_max; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + stmt_text= "SELECT i8, ui8, i16, ui16, i32, ui32, i64, ui64, ui64, " + "cast(ui64 as signed), ui64, cast(ui64 as signed)" + "FROM t1 ORDER BY id ASC"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bind_array[8].buffer_type= MYSQL_TYPE_DOUBLE; + bind_array[8].buffer= (void *) &udouble_val; + + bind_array[9].buffer_type= MYSQL_TYPE_DOUBLE; + bind_array[9].buffer= (void *) &double_val; + + bind_array[10].buffer_type= MYSQL_TYPE_STRING; + bind_array[10].buffer= (void *) &ulonglong_as_string; + bind_array[10].buffer_length= sizeof(ulonglong_as_string); + + bind_array[11].buffer_type= MYSQL_TYPE_STRING; + bind_array[11].buffer= (void *) &longlong_as_string; + bind_array[11].buffer_length= sizeof(longlong_as_string); + + mysql_stmt_bind_result(stmt, bind_array); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(int8_val == int8_min); + DIE_UNLESS(uint8_val == uint8_min); + DIE_UNLESS(int16_val == int16_min); + DIE_UNLESS(uint16_val == uint16_min); + DIE_UNLESS(int32_val == int32_min); + DIE_UNLESS(uint32_val == uint32_min); + DIE_UNLESS(int64_val == int64_min); + DIE_UNLESS(uint64_val == uint64_min); + DIE_UNLESS(double_val == (longlong) uint64_min); + double_tmp= ulonglong2double(uint64_val); + DIE_UNLESS(cmp_double(&udouble_val, &double_tmp)); + DIE_UNLESS(!strcmp(longlong_as_string, "0")); + DIE_UNLESS(!strcmp(ulonglong_as_string, "0")); + + rc= mysql_stmt_fetch(stmt); + + if (!opt_silent) + { + printf("Truncation mask: "); + for (my_bind= bind_array; my_bind < bind_end; my_bind++) + printf("%d", (int) my_bind->error_value); + printf("\n"); + } + DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED || rc == 0); + + DIE_UNLESS(int8_val == int8_max); + DIE_UNLESS(uint8_val == uint8_max); + DIE_UNLESS(int16_val == int16_max); + DIE_UNLESS(uint16_val == uint16_max); + DIE_UNLESS(int32_val == int32_max); + DIE_UNLESS(uint32_val == uint32_max); + DIE_UNLESS(int64_val == int64_max); + DIE_UNLESS(uint64_val == uint64_max); + DIE_UNLESS(double_val == (longlong) uint64_val); + double_tmp= ulonglong2double(uint64_val); + DIE_UNLESS(cmp_double(&udouble_val, &double_tmp)); + DIE_UNLESS(!strcmp(longlong_as_string, "-1")); + DIE_UNLESS(!strcmp(ulonglong_as_string, "18446744073709551615")); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + + stmt_text= "DROP TABLE t1"; + mysql_real_query(mysql, stmt_text, strlen(stmt_text)); +} + + +static void test_union2() +{ + MYSQL_STMT *stmt; + int rc, i; + + myheader("test_union2"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1(col1 INT, \ + col2 VARCHAR(40), \ + col3 SMALLINT, \ + col4 TIMESTAMP)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, + "select col1 FROM t1 where col1=1 union distinct " + "select col1 FROM t1 where col1=2"); + check_stmt(stmt); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 0); + } + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + + +/* + This tests for various mysql_stmt_send_long_data bugs described in #1664 +*/ + +static void test_bug1664() +{ + MYSQL_STMT *stmt; + int rc, int_data; + const char *data; + const char *str_data= "Simple string"; + MYSQL_BIND my_bind[2]; + const char *query= "INSERT INTO test_long_data(col2, col1) VALUES(?, ?)"; + + myheader("test_bug1664"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_long_data"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_long_data(col1 int, col2 long varchar)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + verify_param_count(stmt, 2); + + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *)str_data; + my_bind[0].buffer_length= strlen(str_data); + + my_bind[1].buffer= (void *)&int_data; + my_bind[1].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + int_data= 1; + + /* + Let us supply empty long_data. This should work and should + not break following execution. + */ + data= ""; + rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_col_data("test_long_data", "col1", "1"); + verify_col_data("test_long_data", "col2", ""); + + rc= mysql_query(mysql, "DELETE FROM test_long_data"); + myquery(rc); + + /* This should pass OK */ + data= (char *)"Data"; + rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_col_data("test_long_data", "col1", "1"); + verify_col_data("test_long_data", "col2", "Data"); + + /* clean up */ + rc= mysql_query(mysql, "DELETE FROM test_long_data"); + myquery(rc); + + /* + Now we are changing int parameter and don't do anything + with first parameter. Second mysql_stmt_execute() should run + OK treating this first parameter as string parameter. + */ + + int_data= 2; + /* execute */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_col_data("test_long_data", "col1", "2"); + verify_col_data("test_long_data", "col2", str_data); + + /* clean up */ + rc= mysql_query(mysql, "DELETE FROM test_long_data"); + myquery(rc); + + /* + Now we are sending other long data. It should not be + concatened to previous. + */ + + data= (char *)"SomeOtherData"; + rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_col_data("test_long_data", "col1", "2"); + verify_col_data("test_long_data", "col2", "SomeOtherData"); + + mysql_stmt_close(stmt); + + /* clean up */ + rc= mysql_query(mysql, "DELETE FROM test_long_data"); + myquery(rc); + + /* Now let us test how mysql_stmt_reset works. */ + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + data= (char *)"SomeData"; + rc= mysql_stmt_send_long_data(stmt, 0, data, strlen(data)); + check_execute(stmt, rc); + + rc= mysql_stmt_reset(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + verify_col_data("test_long_data", "col1", "2"); + verify_col_data("test_long_data", "col2", str_data); + + mysql_stmt_close(stmt); + + /* Final clean up */ + rc= mysql_query(mysql, "DROP TABLE test_long_data"); + myquery(rc); +} + + +static void test_order_param() +{ + MYSQL_STMT *stmt; + int rc; + + myheader("test_order_param"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1(a INT, b char(10))"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, + "select sum(a) + 200, 1 from t1 " + " union distinct " + "select sum(a) + 200, 1 from t1 group by b "); + check_stmt(stmt); + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, + "select sum(a) + 200, ? from t1 group by b " + " union distinct " + "select sum(a) + 200, 1 from t1 group by b "); + check_stmt(stmt); + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, + "select sum(a) + 200, ? from t1 " + " union distinct " + "select sum(a) + 200, 1 from t1 group by b "); + check_stmt(stmt); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + + +static void test_union_param() +{ + MYSQL_STMT *stmt; + char *query; + int rc, i; + MYSQL_BIND my_bind[2]; + char my_val[4]; + ulong my_length= 3L; + my_bool my_null= FALSE; + myheader("test_union_param"); + + strmov(my_val, "abc"); + + query= (char*)"select ? as my_col union distinct select ?"; + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + /* bind parameters */ + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + 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[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; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + } + + mysql_stmt_close(stmt); +} + + +static void test_ps_i18n() +{ + MYSQL_STMT *stmt; + int rc; + const char *stmt_text; + MYSQL_BIND bind_array[2]; + + /* Represented as numbers to keep UTF8 tools from clobbering them. */ + const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5"; + const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3"; + char buf1[16], buf2[16]; + ulong buf1_len, buf2_len; + + + myheader("test_ps_i18n"); + + stmt_text= "DROP TABLE IF EXISTS t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + /* + Create table with binary columns, set session character set to cp1251, + client character set to koi8, and make sure that there is conversion + on insert and no conversion on select + */ + + stmt_text= "CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))"; + + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "SET CHARACTER_SET_CLIENT=koi8r, " + "CHARACTER_SET_CONNECTION=cp1251, " + "CHARACTER_SET_RESULTS=koi8r"; + + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + bzero((char*) bind_array, sizeof(bind_array)); + + bind_array[0].buffer_type= MYSQL_TYPE_STRING; + bind_array[0].buffer= (void *) koi8; + bind_array[0].buffer_length= strlen(koi8); + + bind_array[1].buffer_type= MYSQL_TYPE_STRING; + bind_array[1].buffer= (void *) koi8; + bind_array[1].buffer_length= strlen(koi8); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + mysql_stmt_bind_param(stmt, bind_array); + + mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8)); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + stmt_text= "SELECT c1, c2 FROM t1"; + + /* c1 and c2 are binary so no conversion will be done on select */ + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bind_array[0].buffer= buf1; + bind_array[0].buffer_length= sizeof(buf1); + bind_array[0].length= &buf1_len; + + bind_array[1].buffer= buf2; + bind_array[1].buffer_length= sizeof(buf2); + bind_array[1].length= &buf2_len; + + mysql_stmt_bind_result(stmt, bind_array); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(buf1_len == strlen(cp1251)); + DIE_UNLESS(buf2_len == strlen(cp1251)); + DIE_UNLESS(!memcmp(buf1, cp1251, buf1_len)); + DIE_UNLESS(!memcmp(buf2, cp1251, buf1_len)); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + stmt_text= "DROP TABLE IF EXISTS t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + /* + Now create table with two cp1251 columns, set client character + set to koi8 and supply columns of one row as string and another as + binary data. Binary data must not be converted on insert, and both + columns must be converted to client character set on select. + */ + + stmt_text= "CREATE TABLE t1 (c1 VARCHAR(255) CHARACTER SET cp1251, " + "c2 VARCHAR(255) CHARACTER SET cp1251)"; + + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + /* this data must be converted */ + bind_array[0].buffer_type= MYSQL_TYPE_STRING; + bind_array[0].buffer= (void *) koi8; + bind_array[0].buffer_length= strlen(koi8); + + bind_array[1].buffer_type= MYSQL_TYPE_STRING; + bind_array[1].buffer= (void *) koi8; + bind_array[1].buffer_length= strlen(koi8); + + mysql_stmt_bind_param(stmt, bind_array); + + mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8)); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* this data must not be converted */ + bind_array[0].buffer_type= MYSQL_TYPE_BLOB; + bind_array[0].buffer= (void *) cp1251; + bind_array[0].buffer_length= strlen(cp1251); + + bind_array[1].buffer_type= MYSQL_TYPE_BLOB; + bind_array[1].buffer= (void *) cp1251; + bind_array[1].buffer_length= strlen(cp1251); + + mysql_stmt_bind_param(stmt, bind_array); + + mysql_stmt_send_long_data(stmt, 0, cp1251, strlen(cp1251)); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* Fetch data and verify that rows are in koi8 */ + + stmt_text= "SELECT c1, c2 FROM t1"; + + /* c1 and c2 are binary so no conversion will be done on select */ + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bind_array[0].buffer= buf1; + bind_array[0].buffer_length= sizeof(buf1); + bind_array[0].length= &buf1_len; + + bind_array[1].buffer= buf2; + bind_array[1].buffer_length= sizeof(buf2); + bind_array[1].length= &buf2_len; + + mysql_stmt_bind_result(stmt, bind_array); + + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + DIE_UNLESS(buf1_len == strlen(koi8)); + DIE_UNLESS(buf2_len == strlen(koi8)); + DIE_UNLESS(!memcmp(buf1, koi8, buf1_len)); + DIE_UNLESS(!memcmp(buf2, koi8, buf1_len)); + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + mysql_stmt_close(stmt); + + stmt_text= "DROP TABLE t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "SET NAMES DEFAULT"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + +static void test_bug3796() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + const char *concat_arg0= "concat_with_"; + enum { OUT_BUFF_SIZE= 30 }; + char out_buff[OUT_BUFF_SIZE]; + char canonical_buff[OUT_BUFF_SIZE]; + ulong out_length; + const char *stmt_text; + int rc; + + myheader("test_bug3796"); + + /* Create and fill test table */ + stmt_text= "DROP TABLE IF EXISTS t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "CREATE TABLE t1 (a INT, b VARCHAR(30))"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "INSERT INTO t1 VALUES(1, 'ONE'), (2, 'TWO')"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + /* Create statement handle and prepare it with select */ + stmt= mysql_stmt_init(mysql); + stmt_text= "SELECT concat(?, b) FROM t1"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + /* Bind input buffers */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void *) concat_arg0; + my_bind[0].buffer_length= strlen(concat_arg0); + + mysql_stmt_bind_param(stmt, my_bind); + + /* Execute the select statement */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + my_bind[0].buffer= (void *) out_buff; + my_bind[0].buffer_length= OUT_BUFF_SIZE; + my_bind[0].length= &out_length; + + mysql_stmt_bind_result(stmt, my_bind); + + rc= mysql_stmt_fetch(stmt); + if (!opt_silent) + printf("Concat result: '%s'\n", out_buff); + check_execute(stmt, rc); + strmov(canonical_buff, concat_arg0); + strcat(canonical_buff, "ONE"); + DIE_UNLESS(strlen(canonical_buff) == out_length && + strncmp(out_buff, canonical_buff, out_length) == 0); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + strmov(canonical_buff + strlen(concat_arg0), "TWO"); + DIE_UNLESS(strlen(canonical_buff) == out_length && + strncmp(out_buff, canonical_buff, out_length) == 0); + if (!opt_silent) + printf("Concat result: '%s'\n", out_buff); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + + stmt_text= "DROP TABLE IF EXISTS t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + +static void test_bug4026() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + MYSQL_TIME time_in, time_out; + MYSQL_TIME datetime_in, datetime_out; + const char *stmt_text; + int rc; + + myheader("test_bug4026"); + + /* Check that microseconds are inserted and selected successfully */ + + /* Create a statement handle and prepare it with select */ + stmt= mysql_stmt_init(mysql); + stmt_text= "SELECT ?, ?"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + /* Bind input buffers */ + bzero((char*) my_bind, sizeof(my_bind)); + bzero((char*) &time_in, sizeof(time_in)); + bzero((char*) &time_out, sizeof(time_out)); + bzero((char*) &datetime_in, sizeof(datetime_in)); + bzero((char*) &datetime_out, sizeof(datetime_out)); + + my_bind[0].buffer_type= MYSQL_TYPE_TIME; + my_bind[0].buffer= (void *) &time_in; + my_bind[1].buffer_type= MYSQL_TYPE_DATETIME; + my_bind[1].buffer= (void *) &datetime_in; + + time_in.hour= 23; + time_in.minute= 59; + time_in.second= 59; + time_in.second_part= 123456; + /* + This is not necessary, just to make DIE_UNLESS below work: this field + is filled in when time is received from server + */ + time_in.time_type= MYSQL_TIMESTAMP_TIME; + + datetime_in= time_in; + datetime_in.year= 2003; + datetime_in.month= 12; + datetime_in.day= 31; + datetime_in.time_type= MYSQL_TIMESTAMP_DATETIME; + + mysql_stmt_bind_param(stmt, my_bind); + + /* Execute the select statement */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + my_bind[0].buffer= (void *) &time_out; + my_bind[1].buffer= (void *) &datetime_out; + + mysql_stmt_bind_result(stmt, my_bind); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + if (!opt_silent) + { + printf("%d:%d:%d.%lu\n", time_out.hour, time_out.minute, time_out.second, + time_out.second_part); + printf("%d-%d-%d %d:%d:%d.%lu\n", datetime_out.year, datetime_out.month, + datetime_out.day, datetime_out.hour, + datetime_out.minute, datetime_out.second, + datetime_out.second_part); + } + DIE_UNLESS(memcmp(&time_in, &time_out, sizeof(time_in)) == 0); + DIE_UNLESS(memcmp(&datetime_in, &datetime_out, sizeof(datetime_in)) == 0); + mysql_stmt_close(stmt); +} + + +static void test_bug4079() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + const char *stmt_text; + uint32 res; + int rc; + + myheader("test_bug4079"); + + /* Create and fill table */ + mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + mysql_query(mysql, "CREATE TABLE t1 (a int)"); + mysql_query(mysql, "INSERT INTO t1 VALUES (1), (2)"); + + /* Prepare erroneous statement */ + stmt= mysql_stmt_init(mysql); + stmt_text= "SELECT 1 < (SELECT a FROM t1)"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + /* Execute the select statement */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* Bind input buffers */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *) &res; + + mysql_stmt_bind_result(stmt, my_bind); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc != 0 && rc != MYSQL_NO_DATA); + if (!opt_silent) + printf("Got error from mysql_stmt_fetch (as expected):\n%s\n", + mysql_stmt_error(stmt)); + /* buggy version of libmysql hanged up here */ + mysql_stmt_close(stmt); +} + + +static void test_bug4236() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + int rc; + MYSQL_STMT backup; + + myheader("test_bug4236"); + + stmt= mysql_stmt_init(mysql); + + /* mysql_stmt_execute() of statement with statement id= 0 crashed server */ + stmt_text= "SELECT 1"; + /* We need to prepare statement to pass by possible check in libmysql */ + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + /* Hack to check that server works OK if statement wasn't found */ + backup.stmt_id= stmt->stmt_id; + stmt->stmt_id= 0; + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc); + /* Restore original statement id to be able to reprepare it */ + stmt->stmt_id= backup.stmt_id; + + mysql_stmt_close(stmt); +} + + +static void test_bug4030() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[3]; + MYSQL_TIME time_canonical, time_out; + MYSQL_TIME date_canonical, date_out; + MYSQL_TIME datetime_canonical, datetime_out; + const char *stmt_text; + int rc; + + myheader("test_bug4030"); + + /* Check that microseconds are inserted and selected successfully */ + + /* Execute a query with time values in prepared mode */ + stmt= mysql_stmt_init(mysql); + stmt_text= "SELECT '23:59:59.123456', '2003-12-31', " + "'2003-12-31 23:59:59.123456'"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* Bind output buffers */ + bzero((char*) my_bind, sizeof(my_bind)); + bzero((char*) &time_canonical, sizeof(time_canonical)); + bzero((char*) &time_out, sizeof(time_out)); + bzero((char*) &date_canonical, sizeof(date_canonical)); + bzero((char*) &date_out, sizeof(date_out)); + bzero((char*) &datetime_canonical, sizeof(datetime_canonical)); + bzero((char*) &datetime_out, sizeof(datetime_out)); + + my_bind[0].buffer_type= MYSQL_TYPE_TIME; + my_bind[0].buffer= (void *) &time_out; + my_bind[1].buffer_type= MYSQL_TYPE_DATE; + my_bind[1].buffer= (void *) &date_out; + my_bind[2].buffer_type= MYSQL_TYPE_DATETIME; + my_bind[2].buffer= (void *) &datetime_out; + + time_canonical.hour= 23; + time_canonical.minute= 59; + time_canonical.second= 59; + time_canonical.second_part= 123456; + time_canonical.time_type= MYSQL_TIMESTAMP_TIME; + + date_canonical.year= 2003; + date_canonical.month= 12; + date_canonical.day= 31; + date_canonical.time_type= MYSQL_TIMESTAMP_DATE; + + datetime_canonical= time_canonical; + datetime_canonical.year= 2003; + datetime_canonical.month= 12; + datetime_canonical.day= 31; + datetime_canonical.time_type= MYSQL_TIMESTAMP_DATETIME; + + mysql_stmt_bind_result(stmt, my_bind); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + if (!opt_silent) + { + printf("%d:%d:%d.%lu\n", time_out.hour, time_out.minute, time_out.second, + time_out.second_part); + printf("%d-%d-%d\n", date_out.year, date_out.month, date_out.day); + printf("%d-%d-%d %d:%d:%d.%lu\n", datetime_out.year, datetime_out.month, + datetime_out.day, datetime_out.hour, + datetime_out.minute, datetime_out.second, + datetime_out.second_part); + } + DIE_UNLESS(memcmp(&time_canonical, &time_out, sizeof(time_out)) == 0); + DIE_UNLESS(memcmp(&date_canonical, &date_out, sizeof(date_out)) == 0); + DIE_UNLESS(memcmp(&datetime_canonical, &datetime_out, sizeof(datetime_out)) == 0); + mysql_stmt_close(stmt); +} + +static void test_view() +{ + MYSQL_STMT *stmt; + int rc, i; + MYSQL_BIND my_bind[1]; + char str_data[50]; + ulong length = 0L; + long is_null = 0L; + const char *query= + "SELECT COUNT(*) FROM v1 WHERE SERVERNAME=?"; + + myheader("test_view"); + + rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2,t3,v1"); + myquery(rc); + + rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1,t2,t3"); + myquery(rc); + rc= mysql_query(mysql,"CREATE TABLE t1 (" + " SERVERGRP varchar(20) NOT NULL default '', " + " DBINSTANCE varchar(20) NOT NULL default '', " + " PRIMARY KEY (SERVERGRP)) " + " CHARSET=latin1 collate=latin1_bin"); + myquery(rc); + rc= mysql_query(mysql,"CREATE TABLE t2 (" + " SERVERNAME varchar(20) NOT NULL, " + " SERVERGRP varchar(20) NOT NULL, " + " PRIMARY KEY (SERVERNAME)) " + " CHARSET=latin1 COLLATE latin1_bin"); + myquery(rc); + rc= mysql_query(mysql, + "CREATE TABLE t3 (" + " SERVERGRP varchar(20) BINARY NOT NULL, " + " TABNAME varchar(30) NOT NULL, MAPSTATE char(1) NOT NULL, " + " ACTSTATE char(1) NOT NULL , " + " LOCAL_NAME varchar(30) NOT NULL, " + " CHG_DATE varchar(8) NOT NULL default '00000000', " + " CHG_TIME varchar(6) NOT NULL default '000000', " + " MXUSER varchar(12) NOT NULL default '', " + " PRIMARY KEY (SERVERGRP, TABNAME, MAPSTATE, ACTSTATE, " + " LOCAL_NAME)) CHARSET=latin1 COLLATE latin1_bin"); + myquery(rc); + rc= mysql_query(mysql,"CREATE VIEW v1 AS select sql_no_cache" + " T0001.SERVERNAME AS SERVERNAME, T0003.TABNAME AS" + " TABNAME,T0003.LOCAL_NAME AS LOCAL_NAME,T0002.DBINSTANCE AS" + " DBINSTANCE from t2 T0001 join t1 T0002 join t3 T0003 where" + " ((T0002.SERVERGRP = T0001.SERVERGRP) and" + " (T0002.SERVERGRP = T0003.SERVERGRP)" + " and (T0003.MAPSTATE = _latin1'A') and" + " (T0003.ACTSTATE = _latin1' '))"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + strmov(str_data, "TEST"); + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (char *)&str_data; + my_bind[0].buffer_length= 50; + my_bind[0].length= &length; + length= 4; + my_bind[0].is_null= (char*)&is_null; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt,rc); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(1 == rc); + } + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1,t2,t3"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW v1"); + myquery(rc); +} + + +static void test_view_where() +{ + MYSQL_STMT *stmt; + int rc, i; + const char *query= + "select v1.c,v2.c from v1, v2"; + + myheader("test_view_where"); + + rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1,v2"); + myquery(rc); + + rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,v2,t1"); + myquery(rc); + rc= mysql_query(mysql,"CREATE TABLE t1 (a int, b int)"); + myquery(rc); + rc= mysql_query(mysql,"insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10)"); + myquery(rc); + rc= mysql_query(mysql,"create view v1 (c) as select b from t1 where a<3"); + myquery(rc); + rc= mysql_query(mysql,"create view v2 (c) as select b from t1 where a>=3"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(4 == rc); + } + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW v1, v2"); + myquery(rc); +} + + +static void test_view_2where() +{ + MYSQL_STMT *stmt; + int rc, i; + MYSQL_BIND my_bind[8]; + char parms[8][100]; + ulong length[8]; + const char *query= + "select relid, report, handle, log_group, username, variant, type, " + "version, erfdat, erftime, erfname, aedat, aetime, aename, dependvars, " + "inactive from V_LTDX where mandt = ? and relid = ? and report = ? and " + "handle = ? and log_group = ? and username in ( ? , ? ) and type = ?"; + + myheader("test_view_2where"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS LTDX"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW IF EXISTS V_LTDX"); + myquery(rc); + rc= mysql_query(mysql, + "CREATE TABLE LTDX (MANDT char(3) NOT NULL default '000', " + " RELID char(2) NOT NULL, REPORT varchar(40) NOT NULL," + " HANDLE varchar(4) NOT NULL, LOG_GROUP varchar(4) NOT NULL," + " USERNAME varchar(12) NOT NULL," + " VARIANT varchar(12) NOT NULL," + " TYPE char(1) NOT NULL, SRTF2 int(11) NOT NULL," + " VERSION varchar(6) NOT NULL default '000000'," + " ERFDAT varchar(8) NOT NULL default '00000000'," + " ERFTIME varchar(6) NOT NULL default '000000'," + " ERFNAME varchar(12) NOT NULL," + " AEDAT varchar(8) NOT NULL default '00000000'," + " AETIME varchar(6) NOT NULL default '000000'," + " AENAME varchar(12) NOT NULL," + " DEPENDVARS varchar(10) NOT NULL," + " INACTIVE char(1) NOT NULL, CLUSTR smallint(6) NOT NULL," + " CLUSTD blob," + " PRIMARY KEY (MANDT, RELID, REPORT, HANDLE, LOG_GROUP, " + "USERNAME, VARIANT, TYPE, SRTF2))" + " CHARSET=latin1 COLLATE latin1_bin"); + myquery(rc); + rc= mysql_query(mysql, + "CREATE VIEW V_LTDX AS select T0001.MANDT AS " + " MANDT,T0001.RELID AS RELID,T0001.REPORT AS " + " REPORT,T0001.HANDLE AS HANDLE,T0001.LOG_GROUP AS " + " LOG_GROUP,T0001.USERNAME AS USERNAME,T0001.VARIANT AS " + " VARIANT,T0001.TYPE AS TYPE,T0001.VERSION AS " + " VERSION,T0001.ERFDAT AS ERFDAT,T0001.ERFTIME AS " + " ERFTIME,T0001.ERFNAME AS ERFNAME,T0001.AEDAT AS " + " AEDAT,T0001.AETIME AS AETIME,T0001.AENAME AS " + " AENAME,T0001.DEPENDVARS AS DEPENDVARS,T0001.INACTIVE AS " + " INACTIVE from LTDX T0001 where (T0001.SRTF2 = 0)"); + myquery(rc); + bzero((char*) my_bind, sizeof(my_bind)); + for (i=0; i < 8; i++) { + strmov(parms[i], "1"); + my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + my_bind[i].buffer = (char *)&parms[i]; + my_bind[i].buffer_length = 100; + my_bind[i].is_null = 0; + my_bind[i].length = &length[i]; + length[i] = 1; + } + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt,rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(0 == rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP VIEW V_LTDX"); + myquery(rc); + rc= mysql_query(mysql, "DROP TABLE LTDX"); + myquery(rc); +} + + +static void test_view_star() +{ + MYSQL_STMT *stmt; + int rc, i; + MYSQL_BIND my_bind[8]; + char parms[8][100]; + ulong length[8]; + const char *query= "SELECT * FROM vt1 WHERE a IN (?,?)"; + + myheader("test_view_star"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, vt1"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW IF EXISTS t1, vt1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1 (a int)"); + myquery(rc); + rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1"); + myquery(rc); + bzero((char*) my_bind, sizeof(my_bind)); + for (i= 0; i < 2; i++) { + sprintf((char *)&parms[i], "%d", i); + my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + my_bind[i].buffer = (char *)&parms[i]; + my_bind[i].buffer_length = 100; + my_bind[i].is_null = 0; + my_bind[i].length = &length[i]; + length[i] = 1; + } + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt,rc); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(0 == rc); + } + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW vt1"); + myquery(rc); +} + + +static void test_view_insert() +{ + MYSQL_STMT *insert_stmt, *select_stmt; + int rc, i; + MYSQL_BIND my_bind[1]; + int my_val = 0; + ulong my_length = 0L; + long my_null = 0L; + const char *query= + "insert into v1 values (?)"; + + myheader("test_view_insert"); + + rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1"); + myquery(rc); + rc = mysql_query(mysql, "DROP VIEW IF EXISTS t1,v1"); + myquery(rc); + + rc= mysql_query(mysql,"create table t1 (a int, primary key (a))"); + myquery(rc); + + rc= mysql_query(mysql, "create view v1 as select a from t1 where a>=1"); + myquery(rc); + + insert_stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(insert_stmt, query, strlen(query)); + check_execute(insert_stmt, rc); + query= "select * from t1"; + select_stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(select_stmt, query, strlen(query)); + check_execute(select_stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + 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; + rc= mysql_stmt_bind_param(insert_stmt, my_bind); + check_execute(insert_stmt, rc); + + for (i= 0; i < 3; i++) + { + int rowcount= 0; + my_val= i; + + rc= mysql_stmt_execute(insert_stmt); + check_execute(insert_stmt, rc); + + rc= mysql_stmt_execute(select_stmt); + check_execute(select_stmt, rc); + rowcount= (int)my_process_stmt_result(select_stmt); + DIE_UNLESS((i+1) == rowcount); + } + mysql_stmt_close(insert_stmt); + mysql_stmt_close(select_stmt); + + rc= mysql_query(mysql, "DROP VIEW v1"); + myquery(rc); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + + +static void test_left_join_view() +{ + MYSQL_STMT *stmt; + int rc, i; + const char *query= + "select t1.a, v1.x from t1 left join v1 on (t1.a= v1.x);"; + + myheader("test_left_join_view"); + + rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1"); + myquery(rc); + + rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1"); + myquery(rc); + rc= mysql_query(mysql,"CREATE TABLE t1 (a int)"); + myquery(rc); + rc= mysql_query(mysql,"insert into t1 values (1), (2), (3)"); + myquery(rc); + rc= mysql_query(mysql,"create view v1 (x) as select a from t1 where a > 1"); + myquery(rc); + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(3 == rc); + } + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP VIEW v1"); + myquery(rc); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + + +static void test_view_insert_fields() +{ + MYSQL_STMT *stmt; + char parm[11][1000]; + ulong l[11]; + int rc, i; + MYSQL_BIND my_bind[11]; + const char *query= "INSERT INTO `v1` ( `K1C4` ,`K2C4` ,`K3C4` ,`K4N4` ,`F1C4` ,`F2I4` ,`F3N5` ,`F7F8` ,`F6N4` ,`F5C8` ,`F9D8` ) VALUES( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? )"; + + myheader("test_view_insert_fields"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, v1"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW IF EXISTS t1, v1"); + myquery(rc); + rc= mysql_query(mysql, + "CREATE TABLE t1 (K1C4 varchar(4) NOT NULL," + "K2C4 varchar(4) NOT NULL, K3C4 varchar(4) NOT NULL," + "K4N4 varchar(4) NOT NULL default '0000'," + "F1C4 varchar(4) NOT NULL, F2I4 int(11) NOT NULL," + "F3N5 varchar(5) NOT NULL default '00000'," + "F4I4 int(11) NOT NULL default '0', F5C8 varchar(8) NOT NULL," + "F6N4 varchar(4) NOT NULL default '0000'," + "F7F8 double NOT NULL default '0'," + "F8F8 double NOT NULL default '0'," + "F9D8 decimal(8,2) NOT NULL default '0.00'," + "PRIMARY KEY (K1C4,K2C4,K3C4,K4N4)) " + "CHARSET=latin1 COLLATE latin1_bin"); + myquery(rc); + rc= mysql_query(mysql, + "CREATE VIEW v1 AS select sql_no_cache " + " K1C4 AS K1C4, K2C4 AS K2C4, K3C4 AS K3C4, K4N4 AS K4N4, " + " F1C4 AS F1C4, F2I4 AS F2I4, F3N5 AS F3N5," + " F7F8 AS F7F8, F6N4 AS F6N4, F5C8 AS F5C8, F9D8 AS F9D8" + " from t1 T0001"); + + bzero((char*) my_bind, sizeof(my_bind)); + for (i= 0; i < 11; i++) + { + l[i]= 20; + my_bind[i].buffer_type= MYSQL_TYPE_STRING; + my_bind[i].is_null= 0; + my_bind[i].buffer= (char *)&parm[i]; + + memset(parm[i], 0, sizeof parm[i]); + strmov(parm[i], "1"); + my_bind[i].buffer_length= 2; + my_bind[i].length= &l[i]; + } + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_close(stmt); + + query= "select * from t1"; + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= my_process_stmt_result(stmt); + DIE_UNLESS(1 == rc); + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "DROP VIEW v1"); + myquery(rc); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + +} + +static void test_bug5126() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + int32 c1, c2; + const char *stmt_text; + int rc; + + myheader("test_bug5126"); + + stmt_text= "DROP TABLE IF EXISTS t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "CREATE TABLE t1 (a mediumint, b int)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "INSERT INTO t1 VALUES (8386608, 1)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + stmt_text= "SELECT a, b FROM t1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* Bind output buffers */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= &c1; + my_bind[1].buffer_type= MYSQL_TYPE_LONG; + my_bind[1].buffer= &c2; + + mysql_stmt_bind_result(stmt, my_bind); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + DIE_UNLESS(c1 == 8386608 && c2 == 1); + if (!opt_silent) + printf("%ld, %ld\n", (long) c1, (long) c2); + mysql_stmt_close(stmt); +} + + +static void test_bug4231() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + MYSQL_TIME tm[2]; + const char *stmt_text; + int rc; + + myheader("test_bug4231"); + + stmt_text= "DROP TABLE IF EXISTS t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "CREATE TABLE t1 (a int)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "INSERT INTO t1 VALUES (1)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + stmt_text= "SELECT a FROM t1 WHERE ? = ?"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + /* Bind input buffers */ + bzero((char*) my_bind, sizeof(my_bind)); + bzero((char*) tm, sizeof(tm)); + + my_bind[0].buffer_type= MYSQL_TYPE_DATE; + my_bind[0].buffer= &tm[0]; + my_bind[1].buffer_type= MYSQL_TYPE_DATE; + my_bind[1].buffer= &tm[1]; + + mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + /* + First set server-side params to some non-zero non-equal values: + then we will check that they are not used when client sends + new (zero) times. + */ + tm[0].time_type = MYSQL_TIMESTAMP_DATE; + tm[0].year = 2000; + tm[0].month = 1; + tm[0].day = 1; + tm[1]= tm[0]; + --tm[1].year; /* tm[0] != tm[1] */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + + /* binds are unequal, no rows should be returned */ + DIE_UNLESS(rc == MYSQL_NO_DATA); + + /* Set one of the dates to zero */ + tm[0].year= tm[0].month= tm[0].day= 0; + tm[1]= tm[0]; + mysql_stmt_execute(stmt); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + + mysql_stmt_close(stmt); + stmt_text= "DROP TABLE t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + +static void test_bug5399() +{ + /* + Ascii 97 is 'a', which gets mapped to Ascii 65 'A' unless internal + statement id hash in the server uses binary collation. + */ +#define NUM_OF_USED_STMT 97 + MYSQL_STMT *stmt_list[NUM_OF_USED_STMT]; + MYSQL_STMT **stmt; + MYSQL_BIND my_bind[1]; + char buff[600]; + int rc; + int32 no; + + myheader("test_bug5399"); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= &no; + + for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt) + { + sprintf(buff, "select %d", (int) (stmt - stmt_list)); + *stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(*stmt, buff, strlen(buff)); + check_execute(*stmt, rc); + mysql_stmt_bind_result(*stmt, my_bind); + } + if (!opt_silent) + printf("%d statements prepared.\n", NUM_OF_USED_STMT); + + for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt) + { + rc= mysql_stmt_execute(*stmt); + check_execute(*stmt, rc); + rc= mysql_stmt_store_result(*stmt); + check_execute(*stmt, rc); + rc= mysql_stmt_fetch(*stmt); + DIE_UNLESS(rc == 0); + DIE_UNLESS((int32) (stmt - stmt_list) == no); + } + + for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt) + mysql_stmt_close(*stmt); +#undef NUM_OF_USED_STMT +} + + +static void test_bug5194() +{ + MYSQL_STMT *stmt; + MYSQL_BIND *my_bind; + char *query; + char *param_str; + int param_str_length; + const char *stmt_text; + int rc; + float float_array[250] = + { + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25 + }; + float *fa_ptr= float_array; + /* Number of columns per row */ + const int COLUMN_COUNT= sizeof(float_array)/sizeof(*float_array); + /* Number of rows per bulk insert to start with */ + const int MIN_ROWS_PER_INSERT= 262; + /* Max number of rows per bulk insert to end with */ + const int MAX_ROWS_PER_INSERT= 300; + const int MAX_PARAM_COUNT= COLUMN_COUNT*MAX_ROWS_PER_INSERT; + const char *query_template= "insert into t1 values %s"; + const int CHARS_PER_PARAM= 5; /* space needed to place ", ?" in the query */ + const int uint16_max= 65535; + int nrows, i; + + myheader("test_bug5194"); + + stmt_text= "drop table if exists t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + + stmt_text= "create table if not exists t1" + "(c1 float, c2 float, c3 float, c4 float, c5 float, c6 float, " + "c7 float, c8 float, c9 float, c10 float, c11 float, c12 float, " + "c13 float, c14 float, c15 float, c16 float, c17 float, c18 float, " + "c19 float, c20 float, c21 float, c22 float, c23 float, c24 float, " + "c25 float, c26 float, c27 float, c28 float, c29 float, c30 float, " + "c31 float, c32 float, c33 float, c34 float, c35 float, c36 float, " + "c37 float, c38 float, c39 float, c40 float, c41 float, c42 float, " + "c43 float, c44 float, c45 float, c46 float, c47 float, c48 float, " + "c49 float, c50 float, c51 float, c52 float, c53 float, c54 float, " + "c55 float, c56 float, c57 float, c58 float, c59 float, c60 float, " + "c61 float, c62 float, c63 float, c64 float, c65 float, c66 float, " + "c67 float, c68 float, c69 float, c70 float, c71 float, c72 float, " + "c73 float, c74 float, c75 float, c76 float, c77 float, c78 float, " + "c79 float, c80 float, c81 float, c82 float, c83 float, c84 float, " + "c85 float, c86 float, c87 float, c88 float, c89 float, c90 float, " + "c91 float, c92 float, c93 float, c94 float, c95 float, c96 float, " + "c97 float, c98 float, c99 float, c100 float, c101 float, c102 float, " + "c103 float, c104 float, c105 float, c106 float, c107 float, c108 float, " + "c109 float, c110 float, c111 float, c112 float, c113 float, c114 float, " + "c115 float, c116 float, c117 float, c118 float, c119 float, c120 float, " + "c121 float, c122 float, c123 float, c124 float, c125 float, c126 float, " + "c127 float, c128 float, c129 float, c130 float, c131 float, c132 float, " + "c133 float, c134 float, c135 float, c136 float, c137 float, c138 float, " + "c139 float, c140 float, c141 float, c142 float, c143 float, c144 float, " + "c145 float, c146 float, c147 float, c148 float, c149 float, c150 float, " + "c151 float, c152 float, c153 float, c154 float, c155 float, c156 float, " + "c157 float, c158 float, c159 float, c160 float, c161 float, c162 float, " + "c163 float, c164 float, c165 float, c166 float, c167 float, c168 float, " + "c169 float, c170 float, c171 float, c172 float, c173 float, c174 float, " + "c175 float, c176 float, c177 float, c178 float, c179 float, c180 float, " + "c181 float, c182 float, c183 float, c184 float, c185 float, c186 float, " + "c187 float, c188 float, c189 float, c190 float, c191 float, c192 float, " + "c193 float, c194 float, c195 float, c196 float, c197 float, c198 float, " + "c199 float, c200 float, c201 float, c202 float, c203 float, c204 float, " + "c205 float, c206 float, c207 float, c208 float, c209 float, c210 float, " + "c211 float, c212 float, c213 float, c214 float, c215 float, c216 float, " + "c217 float, c218 float, c219 float, c220 float, c221 float, c222 float, " + "c223 float, c224 float, c225 float, c226 float, c227 float, c228 float, " + "c229 float, c230 float, c231 float, c232 float, c233 float, c234 float, " + "c235 float, c236 float, c237 float, c238 float, c239 float, c240 float, " + "c241 float, c242 float, c243 float, c244 float, c245 float, c246 float, " + "c247 float, c248 float, c249 float, c250 float)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + my_bind= (MYSQL_BIND*) malloc(MAX_PARAM_COUNT * sizeof(MYSQL_BIND)); + query= (char*) malloc(strlen(query_template) + + MAX_PARAM_COUNT * CHARS_PER_PARAM + 1); + param_str= (char*) malloc(COLUMN_COUNT * CHARS_PER_PARAM); + + if (my_bind == 0 || query == 0 || param_str == 0) + { + fprintf(stderr, "Can't allocate enough memory for query structs\n"); + if (my_bind) + free(my_bind); + if (query) + free(query); + if (param_str) + free(param_str); + return; + } + + stmt= mysql_stmt_init(mysql); + + /* setup a template for one row of parameters */ + sprintf(param_str, "("); + for (i= 1; i < COLUMN_COUNT; ++i) + strcat(param_str, "?, "); + strcat(param_str, "?)"); + param_str_length= strlen(param_str); + + /* setup bind array */ + bzero((char*) my_bind, MAX_PARAM_COUNT * sizeof(MYSQL_BIND)); + for (i= 0; i < MAX_PARAM_COUNT; ++i) + { + my_bind[i].buffer_type= MYSQL_TYPE_FLOAT; + my_bind[i].buffer= fa_ptr; + if (++fa_ptr == float_array + COLUMN_COUNT) + fa_ptr= float_array; + } + + /* + Test each number of rows per bulk insert, so that we can see where + MySQL fails. + */ + for (nrows= MIN_ROWS_PER_INSERT; nrows <= MAX_ROWS_PER_INSERT; ++nrows) + { + char *query_ptr; + /* Create statement text for current number of rows */ + sprintf(query, query_template, param_str); + query_ptr= query + strlen(query); + for (i= 1; i < nrows; ++i) + { + memcpy(query_ptr, ", ", 2); + query_ptr+= 2; + memcpy(query_ptr, param_str, param_str_length); + query_ptr+= param_str_length; + } + *query_ptr= '\0'; + + rc= mysql_stmt_prepare(stmt, query, (ulong)(query_ptr - query)); + if (rc && nrows * COLUMN_COUNT > uint16_max) + { + if (!opt_silent) + printf("Failed to prepare a statement with %d placeholders " + "(as expected).\n", nrows * COLUMN_COUNT); + break; + } + else + check_execute(stmt, rc); + + if (!opt_silent) + printf("Insert: query length= %d, row count= %d, param count= %lu\n", + (int) strlen(query), nrows, mysql_stmt_param_count(stmt)); + + /* bind the parameter array and execute the query */ + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_reset(stmt); + } + + mysql_stmt_close(stmt); + free(my_bind); + free(query); + free(param_str); + stmt_text= "drop table t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + +static void test_bug5315() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + int rc; + + myheader("test_bug5315"); + + stmt_text= "SELECT 1"; + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + DIE_UNLESS(rc == 0); + if (!opt_silent) + printf("Executing mysql_change_user\n"); + mysql_change_user(mysql, opt_user, opt_password, current_db); + if (!opt_silent) + printf("Executing mysql_stmt_execute\n"); + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc != 0); + if (rc) + { + if (!opt_silent) + printf("Got error (as expected): '%s'\n", mysql_stmt_error(stmt)); + } + /* check that connection is OK */ + if (!opt_silent) + printf("Executing mysql_stmt_close\n"); + mysql_stmt_close(stmt); + if (!opt_silent) + printf("Executing mysql_stmt_init\n"); + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + DIE_UNLESS(rc == 0); + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + mysql_stmt_close(stmt); +} + + +static void test_bug6049() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + MYSQL_RES *res; + MYSQL_ROW row; + const char *stmt_text; + char buffer[30]; + ulong length; + int rc; + + myheader("test_bug6049"); + + stmt_text= "SELECT MAKETIME(-25, 12, 12)"; + + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + res= mysql_store_result(mysql); + row= mysql_fetch_row(res); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type = MYSQL_TYPE_STRING; + my_bind[0].buffer = &buffer; + my_bind[0].buffer_length = sizeof(buffer); + my_bind[0].length = &length; + + mysql_stmt_bind_result(stmt, my_bind); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + + if (!opt_silent) + { + printf("Result from query: %s\n", row[0]); + printf("Result from prepared statement: %s\n", (char*) buffer); + } + + DIE_UNLESS(strcmp(row[0], (char*) buffer) == 0); + + mysql_free_result(res); + mysql_stmt_close(stmt); +} + + +static void test_bug6058() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + MYSQL_RES *res; + MYSQL_ROW row; + const char *stmt_text; + char buffer[30]; + ulong length; + int rc; + + myheader("test_bug6058"); + + rc= mysql_query(mysql, "SET SQL_MODE=''"); + myquery(rc); + + stmt_text= "SELECT CAST('0000-00-00' AS DATE)"; + + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + res= mysql_store_result(mysql); + row= mysql_fetch_row(res); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type = MYSQL_TYPE_STRING; + my_bind[0].buffer = &buffer; + my_bind[0].buffer_length = sizeof(buffer); + my_bind[0].length = &length; + + mysql_stmt_bind_result(stmt, my_bind); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + + if (!opt_silent) + { + printf("Result from query: %s\n", row[0]); + printf("Result from prepared statement: %s\n", buffer); + } + + DIE_UNLESS(strcmp(row[0], buffer) == 0); + + mysql_free_result(res); + mysql_stmt_close(stmt); +} + + +static void test_bug6059() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + + myheader("test_bug6059"); + + stmt_text= "SELECT 'foo' INTO OUTFILE 'x.3'"; + + stmt= mysql_stmt_init(mysql); + (void) mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + DIE_UNLESS(mysql_stmt_field_count(stmt) == 0); + mysql_stmt_close(stmt); +} + + +static void test_bug6046() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + int rc; + short b= 1; + MYSQL_BIND my_bind[1]; + + myheader("test_bug6046"); + + stmt_text= "DROP TABLE IF EXISTS t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "CREATE TABLE t1 (a int, b int)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "INSERT INTO t1 VALUES (1,1),(2,2),(3,1),(4,2)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + stmt_text= "SELECT t1.a FROM t1 NATURAL JOIN t1 as X1 " + "WHERE t1.b > ? ORDER BY t1.a"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + b= 1; + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer= &b; + my_bind[0].buffer_type= MYSQL_TYPE_SHORT; + + mysql_stmt_bind_param(stmt, my_bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_store_result(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); +} + + + +static void test_basic_cursors() +{ + const char *basic_tables[]= + { + "DROP TABLE IF EXISTS t1, t2", + + "CREATE TABLE t1 " + "(id INTEGER NOT NULL PRIMARY KEY, " + " name VARCHAR(20) NOT NULL)", + + "INSERT INTO t1 (id, name) VALUES " + " (2, 'Ja'), (3, 'Ede'), " + " (4, 'Haag'), (5, 'Kabul'), " + " (6, 'Almere'), (7, 'Utrecht'), " + " (8, 'Qandahar'), (9, 'Amsterdam'), " + " (10, 'Amersfoort'), (11, 'Constantine')", + + "CREATE TABLE t2 " + "(id INTEGER NOT NULL PRIMARY KEY, " + " name VARCHAR(20) NOT NULL)", + + "INSERT INTO t2 (id, name) VALUES " + " (4, 'Guam'), (5, 'Aruba'), " + " (6, 'Angola'), (7, 'Albania'), " + " (8, 'Anguilla'), (9, 'Argentina'), " + " (10, 'Azerbaijan'), (11, 'Afghanistan'), " + " (12, 'Burkina Faso'), (13, 'Faroe Islands')" + }; + const char *queries[]= + { + "SELECT * FROM t1", + "SELECT * FROM t2" + }; + + DBUG_ENTER("test_basic_cursors"); + myheader("test_basic_cursors"); + + fill_tables(basic_tables, sizeof(basic_tables)/sizeof(*basic_tables)); + + fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH); + fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT); + DBUG_VOID_RETURN; +} + + +static void test_cursors_with_union() +{ + const char *queries[]= + { + "SELECT t1.name FROM t1 UNION SELECT t2.name FROM t2", + "SELECT t1.id FROM t1 WHERE t1.id < 5" + }; + myheader("test_cursors_with_union"); + fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH); + fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT); +} + + +static void test_cursors_with_procedure() +{ + const char *queries[]= + { + "SELECT * FROM t1 procedure analyse()" + }; + myheader("test_cursors_with_procedure"); + fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH); + fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT); +} + + +/* + Altough mysql_create_db(), mysql_rm_db() are deprecated since 4.0 they + should not crash server and should not hang in case of errors. + + Since those functions can't be seen in modern API (unless client library + was compiled with USE_OLD_FUNCTIONS define) we use simple_command() macro. +*/ +static void test_bug6081() +{ + int rc; + myheader("test_bug6081"); + + rc= simple_command(mysql, COM_DROP_DB, (uchar*) current_db, + (ulong)strlen(current_db), 0); + if (rc == 0 && mysql_errno(mysql) != ER_UNKNOWN_COM_ERROR) + { + myerror(NULL); /* purecov: inspected */ + die(__FILE__, __LINE__, "COM_DROP_DB failed"); /* purecov: inspected */ + } + rc= simple_command(mysql, COM_DROP_DB, (uchar*) current_db, + (ulong)strlen(current_db), 0); + myquery_r(rc); + rc= simple_command(mysql, COM_CREATE_DB, (uchar*) current_db, + (ulong)strlen(current_db), 0); + if (rc == 0 && mysql_errno(mysql) != ER_UNKNOWN_COM_ERROR) + { + myerror(NULL); /* purecov: inspected */ + die(__FILE__, __LINE__, "COM_CREATE_DB failed"); /* purecov: inspected */ + } + rc= simple_command(mysql, COM_CREATE_DB, (uchar*) current_db, + (ulong)strlen(current_db), 0); + myquery_r(rc); + rc= mysql_select_db(mysql, current_db); + myquery(rc); +} + + +static void test_bug6096() +{ + MYSQL_STMT *stmt; + MYSQL_RES *query_result, *stmt_metadata; + const char *stmt_text; + MYSQL_BIND my_bind[12]; + MYSQL_FIELD *query_field_list, *stmt_field_list; + ulong query_field_count, stmt_field_count; + int rc; + my_bool update_max_length= TRUE; + uint i; + + myheader("test_bug6096"); + + stmt_text= "drop table if exists t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + mysql_query(mysql, "set sql_mode=''"); + stmt_text= "create table t1 (c_tinyint tinyint, c_smallint smallint, " + " c_mediumint mediumint, c_int int, " + " c_bigint bigint, c_float float, " + " c_double double, c_varchar varchar(20), " + " c_char char(20), c_time time, c_date date, " + " c_datetime datetime)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "insert into t1 values (-100, -20000, 30000000, 4, 8, 1.0, " + "2.0, 'abc', 'def', now(), now(), now())"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "select * from t1"; + + /* Run select in prepared and non-prepared mode and compare metadata */ + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + query_result= mysql_store_result(mysql); + query_field_list= mysql_fetch_fields(query_result); + query_field_count= mysql_num_fields(query_result); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, + (void*) &update_max_length); + mysql_stmt_store_result(stmt); + stmt_metadata= mysql_stmt_result_metadata(stmt); + stmt_field_list= mysql_fetch_fields(stmt_metadata); + stmt_field_count= mysql_num_fields(stmt_metadata); + DIE_UNLESS(stmt_field_count == query_field_count); + + /* Print out and check the metadata */ + + if (!opt_silent) + { + printf(" ------------------------------------------------------------\n"); + printf(" | Metadata \n"); + printf(" ------------------------------------------------------------\n"); + printf(" | Query | Prepared statement \n"); + printf(" ------------------------------------------------------------\n"); + printf(" field name | length | max_length | length | max_length\n"); + printf(" ------------------------------------------------------------\n"); + + for (i= 0; i < query_field_count; ++i) + { + MYSQL_FIELD *f1= &query_field_list[i], *f2= &stmt_field_list[i]; + printf(" %-11s | %9lu | %10lu | %9lu | %10lu \n", + f1->name, f1->length, f1->max_length, f2->length, f2->max_length); + DIE_UNLESS(f1->length == f2->length); + } + printf(" ---------------------------------------------------------------\n"); + } + + /* Bind and fetch the data */ + + bzero((char*) my_bind, sizeof(my_bind)); + for (i= 0; i < stmt_field_count; ++i) + { + my_bind[i].buffer_type= MYSQL_TYPE_STRING; + my_bind[i].buffer_length= stmt_field_list[i].max_length + 1; + my_bind[i].buffer= malloc(my_bind[i].buffer_length); + } + mysql_stmt_bind_result(stmt, my_bind); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + /* Clean up */ + + for (i= 0; i < stmt_field_count; ++i) + free(my_bind[i].buffer); + mysql_stmt_close(stmt); + mysql_free_result(query_result); + mysql_free_result(stmt_metadata); + stmt_text= "drop table t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + +/* + Test of basic checks that are performed in server for components + of MYSQL_TIME parameters. +*/ + +static void test_datetime_ranges() +{ + const char *stmt_text; + int rc, i; + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[6]; + MYSQL_TIME tm[6]; + + myheader("test_datetime_ranges"); + + stmt_text= "drop table if exists t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create table t1 (year datetime, month datetime, day datetime, " + "hour datetime, min datetime, sec datetime)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, + "INSERT INTO t1 VALUES (?, ?, ?, ?, ?, ?)"); + check_stmt(stmt); + verify_param_count(stmt, 6); + + bzero((char*) my_bind, sizeof(my_bind)); + for (i= 0; i < 6; i++) + { + my_bind[i].buffer_type= MYSQL_TYPE_DATETIME; + my_bind[i].buffer= &tm[i]; + } + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + tm[0].year= 2004; tm[0].month= 11; tm[0].day= 10; + tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30; + tm[0].second_part= 0; tm[0].neg= 0; + + tm[5]= tm[4]= tm[3]= tm[2]= tm[1]= tm[0]; + tm[0].year= 10000; tm[1].month= 13; tm[2].day= 32; + tm[3].hour= 24; tm[4].minute= 60; tm[5].second= 60; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + my_process_warnings(mysql, 6); + + verify_col_data("t1", "year", "0000-00-00 00:00:00"); + verify_col_data("t1", "month", "0000-00-00 00:00:00"); + verify_col_data("t1", "day", "0000-00-00 00:00:00"); + verify_col_data("t1", "hour", "0000-00-00 00:00:00"); + verify_col_data("t1", "min", "0000-00-00 00:00:00"); + verify_col_data("t1", "sec", "0000-00-00 00:00:00"); + + mysql_stmt_close(stmt); + + stmt_text= "delete from t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "INSERT INTO t1 (year, month, day) " + "VALUES (?, ?, ?)"); + check_stmt(stmt); + verify_param_count(stmt, 3); + + /* + We reuse contents of bind and tm arrays left from previous part of test. + */ + for (i= 0; i < 3; i++) + my_bind[i].buffer_type= MYSQL_TYPE_DATE; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + my_process_warnings(mysql, 3); + + verify_col_data("t1", "year", "0000-00-00 00:00:00"); + verify_col_data("t1", "month", "0000-00-00 00:00:00"); + verify_col_data("t1", "day", "0000-00-00 00:00:00"); + + mysql_stmt_close(stmt); + + stmt_text= "drop table t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create table t1 (day_ovfl time, day time, hour time, min time, sec time)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, + "INSERT INTO t1 VALUES (?, ?, ?, ?, ?)"); + check_stmt(stmt); + verify_param_count(stmt, 5); + + /* + Again we reuse what we can from previous part of test. + */ + for (i= 0; i < 5; i++) + my_bind[i].buffer_type= MYSQL_TYPE_TIME; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + tm[0].year= 0; tm[0].month= 0; tm[0].day= 10; + tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30; + tm[0].second_part= 0; tm[0].neg= 0; + + tm[4]= tm[3]= tm[2]= tm[1]= tm[0]; + tm[0].day= 35; tm[1].day= 34; tm[2].hour= 30; tm[3].minute= 60; tm[4].second= 60; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + my_process_warnings(mysql, 2); + + verify_col_data("t1", "day_ovfl", "838:59:59"); + verify_col_data("t1", "day", "828:30:30"); + verify_col_data("t1", "hour", "270:30:30"); + verify_col_data("t1", "min", "00:00:00"); + verify_col_data("t1", "sec", "00:00:00"); + + mysql_stmt_close(stmt); + + stmt_text= "drop table t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + +/* + This test is used in: + mysql-test/suite/binlog/binlog_stm_datetime_ranges_mdev15289.test +*/ +static void test_datetime_ranges_mdev15289() +{ + const char *stmt_text; + int rc, i; + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[4]; + MYSQL_TIME tm[4]; + + myheader("test_datetime_ranges_mdev15289"); + + stmt_text= "SET sql_mode=''"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create or replace table t1 " + "(t time, d date, dt datetime,ts timestamp)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "INSERT INTO t1 VALUES (?, ?, ?, ?)"); + check_stmt(stmt); + verify_param_count(stmt, 4); + + /*** Testing DATETIME ***/ + bzero((char*) my_bind, sizeof(my_bind)); + for (i= 0; i < 4; i++) + { + my_bind[i].buffer_type= MYSQL_TYPE_DATETIME; + my_bind[i].buffer= &tm[i]; + } + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + /* Notice bad year */ + tm[0].year= 20010; tm[0].month= 1; tm[0].day= 2; + tm[0].hour= 03; tm[0].minute= 04; tm[0].second= 05; + tm[0].second_part= 0; tm[0].neg= 0; + tm[0].time_type= MYSQL_TIMESTAMP_DATETIME; + tm[3]= tm[2]= tm[1]= tm[0]; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + my_process_warnings(mysql, 4); + + verify_col_data("t1", "t", "00:00:00"); + verify_col_data("t1", "d", "0000-00-00"); + verify_col_data("t1", "dt", "0000-00-00 00:00:00"); + verify_col_data("t1", "ts", "0000-00-00 00:00:00"); + + /*** Testing DATE ***/ + bzero((char*) my_bind, sizeof(my_bind)); + for (i= 0; i < 4; i++) + { + my_bind[i].buffer_type= MYSQL_TYPE_DATE; + my_bind[i].buffer= &tm[i]; + } + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + /* Notice bad year */ + tm[0].year= 20010; tm[0].month= 1; tm[0].day= 2; + tm[0].hour= 00; tm[0].minute= 00; tm[0].second= 00; + tm[0].second_part= 0; tm[0].neg= 0; + tm[0].time_type= MYSQL_TIMESTAMP_DATE; + tm[3]= tm[2]= tm[1]= tm[0]; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + my_process_warnings(mysql, 4); + + verify_col_data("t1", "t", "00:00:00"); + verify_col_data("t1", "d", "0000-00-00"); + verify_col_data("t1", "dt", "0000-00-00 00:00:00"); + verify_col_data("t1", "ts", "0000-00-00 00:00:00"); + + /*** Testing TIME ***/ + bzero((char*) my_bind, sizeof(my_bind)); + for (i= 0; i < 4; i++) + { + my_bind[i].buffer_type= MYSQL_TYPE_TIME; + my_bind[i].buffer= &tm[i]; + } + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + /* Notice bad hour */ + tm[0].year= 0; tm[0].month= 0; tm[0].day= 0; + tm[0].hour= 100; tm[0].minute= 64; tm[0].second= 05; + tm[0].second_part= 0; tm[0].neg= 0; + tm[0].time_type= MYSQL_TIMESTAMP_TIME; + tm[3]= tm[2]= tm[1]= tm[0]; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + my_process_warnings(mysql, 4); + + verify_col_data("t1", "t", "00:00:00"); + verify_col_data("t1", "d", "0000-00-00"); + verify_col_data("t1", "dt", "0000-00-00 00:00:00"); + verify_col_data("t1", "ts", "0000-00-00 00:00:00"); + + mysql_stmt_close(stmt); + + stmt_text= "drop table t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + +static void test_bug4172() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[3]; + const char *stmt_text; + MYSQL_RES *res; + MYSQL_ROW row; + int rc; + char f[100], d[100], e[100]; + ulong f_len, d_len, e_len; + + myheader("test_bug4172"); + + mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + mysql_query(mysql, "CREATE TABLE t1 (f float, d double, e decimal(10,4))"); + mysql_query(mysql, "INSERT INTO t1 VALUES (12345.1234, 123456.123456, " + "123456.1234)"); + + stmt= mysql_stmt_init(mysql); + stmt_text= "SELECT f, d, e FROM t1"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= f; + my_bind[0].buffer_length= sizeof(f); + my_bind[0].length= &f_len; + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= d; + my_bind[1].buffer_length= sizeof(d); + my_bind[1].length= &d_len; + my_bind[2].buffer_type= MYSQL_TYPE_STRING; + my_bind[2].buffer= e; + my_bind[2].buffer_length= sizeof(e); + my_bind[2].length= &e_len; + + mysql_stmt_bind_result(stmt, my_bind); + + mysql_stmt_store_result(stmt); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + res= mysql_store_result(mysql); + row= mysql_fetch_row(res); + + if (!opt_silent) + { + printf("Binary protocol: float=%s, double=%s, decimal(10,4)=%s\n", + f, d, e); + printf("Text protocol: float=%s, double=%s, decimal(10,4)=%s\n", + row[0], row[1], row[2]); + } + DIE_UNLESS(!strcmp(f, row[0]) && !strcmp(d, row[1]) && !strcmp(e, row[2])); + + mysql_free_result(res); + mysql_stmt_close(stmt); +} + + +static void test_conversion() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + int rc; + MYSQL_BIND my_bind[1]; + uchar buff[4]; + ulong length; + + myheader("test_conversion"); + + stmt_text= "DROP TABLE IF EXISTS t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "CREATE TABLE t1 (a TEXT) DEFAULT CHARSET latin1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "SET character_set_connection=utf8, character_set_client=utf8, " + " character_set_results=latin1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + stmt_text= "INSERT INTO t1 (a) VALUES (?)"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer= (char*) buff; + my_bind[0].length= &length; + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + + mysql_stmt_bind_param(stmt, my_bind); + + buff[0]= (uchar) 0xC3; + buff[1]= (uchar) 0xA0; + length= 2; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + stmt_text= "SELECT a FROM t1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + my_bind[0].buffer_length= sizeof(buff); + mysql_stmt_bind_result(stmt, my_bind); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + DIE_UNLESS(length == 1); + DIE_UNLESS(buff[0] == 0xE0); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + stmt_text= "DROP TABLE t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "SET NAMES DEFAULT"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + +static void test_rewind(void) +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind; + int rc = 0; + const char *stmt_text; + long unsigned int length=4, Data=0; + my_bool isnull=0; + + myheader("test_rewind"); + + stmt_text= "CREATE TABLE t1 (a int)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "INSERT INTO t1 VALUES(2),(3),(4)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + stmt_text= "SELECT * FROM t1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + bzero((char*) &my_bind, sizeof(MYSQL_BIND)); + my_bind.buffer_type= MYSQL_TYPE_LONG; + my_bind.buffer= (void *)&Data; /* this buffer won't be altered */ + my_bind.length= &length; + my_bind.is_null= &isnull; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_bind_result(stmt, &my_bind); + DIE_UNLESS(rc == 0); + + /* retreive all result sets till we are at the end */ + while(!mysql_stmt_fetch(stmt)) + if (!opt_silent) + printf("fetched result:%ld\n", Data); + + DIE_UNLESS(rc != MYSQL_NO_DATA); + + /* seek to the first row */ + mysql_stmt_data_seek(stmt, 0); + + /* now we should be able to fetch the results again */ + /* but mysql_stmt_fetch returns MYSQL_NO_DATA */ + while(!(rc= mysql_stmt_fetch(stmt))) + if (!opt_silent) + printf("fetched result after seek:%ld\n", Data); + + DIE_UNLESS(rc == MYSQL_NO_DATA); + + stmt_text= "DROP TABLE t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + rc= mysql_stmt_free_result(stmt); + rc= mysql_stmt_close(stmt); +} + + +static void test_truncation() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + int rc; + uint bind_count; + MYSQL_BIND *bind_array, *my_bind; + + myheader("test_truncation"); + + /* Prepare the test table */ + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + stmt_text= "create table t1 (" + "i8 tinyint, ui8 tinyint unsigned, " + "i16 smallint, i16_1 smallint, " + "ui16 smallint unsigned, i32 int, i32_1 int, " + "d double, d_1 double, ch char(30), ch_1 char(30), " + "tx text, tx_1 text, ch_2 char(30) " + ")"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + { + const char insert_text[]= + "insert into t1 VALUES (" + "-10, " /* i8 */ + "200, " /* ui8 */ + "32000, " /* i16 */ + "-32767, " /* i16_1 */ + "64000, " /* ui16 */ + "1073741824, " /* i32 */ + "1073741825, " /* i32_1 */ + "123.456, " /* d */ + "-12345678910, " /* d_1 */ + "'111111111111111111111111111111',"/* ch */ + "'abcdef', " /* ch_1 */ + "'12345 ', " /* tx */ + "'12345.67 ', " /* tx_1 */ + "'12345.67abc'" /* ch_2 */ + ")"; + rc= mysql_real_query(mysql, insert_text, strlen(insert_text)); + myquery(rc); + } + + stmt_text= "select i8 c1, i8 c2, ui8 c3, i16_1 c4, ui16 c5, " + " i16 c6, ui16 c7, i32 c8, i32_1 c9, i32_1 c10, " + " d c11, d_1 c12, d_1 c13, ch c14, ch_1 c15, tx c16, " + " tx_1 c17, ch_2 c18 " + "from t1"; + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + bind_count= (uint) mysql_stmt_field_count(stmt); + + /*************** Fill in the bind structure and bind it **************/ + bind_array= malloc(sizeof(MYSQL_BIND) * bind_count); + bzero((char*) bind_array, sizeof(MYSQL_BIND) * bind_count); + for (my_bind= bind_array; my_bind < bind_array + bind_count; my_bind++) + my_bind->error= &my_bind->error_value; + my_bind= bind_array; + + my_bind->buffer= malloc(sizeof(uint8)); + my_bind->buffer_type= MYSQL_TYPE_TINY; + my_bind->is_unsigned= TRUE; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(uint32)); + my_bind->buffer_type= MYSQL_TYPE_LONG; + my_bind->is_unsigned= TRUE; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(int8)); + my_bind->buffer_type= MYSQL_TYPE_TINY; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(uint16)); + my_bind->buffer_type= MYSQL_TYPE_SHORT; + my_bind->is_unsigned= TRUE; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(int16)); + my_bind->buffer_type= MYSQL_TYPE_SHORT; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(uint16)); + my_bind->buffer_type= MYSQL_TYPE_SHORT; + my_bind->is_unsigned= TRUE; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(int8)); + my_bind->buffer_type= MYSQL_TYPE_TINY; + my_bind->is_unsigned= TRUE; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(float)); + my_bind->buffer_type= MYSQL_TYPE_FLOAT; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(float)); + my_bind->buffer_type= MYSQL_TYPE_FLOAT; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(double)); + my_bind->buffer_type= MYSQL_TYPE_DOUBLE; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(longlong)); + my_bind->buffer_type= MYSQL_TYPE_LONGLONG; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(ulonglong)); + my_bind->buffer_type= MYSQL_TYPE_LONGLONG; + my_bind->is_unsigned= TRUE; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(longlong)); + my_bind->buffer_type= MYSQL_TYPE_LONGLONG; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(longlong)); + my_bind->buffer_type= MYSQL_TYPE_LONGLONG; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(longlong)); + my_bind->buffer_type= MYSQL_TYPE_LONGLONG; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(longlong)); + my_bind->buffer_type= MYSQL_TYPE_LONGLONG; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(double)); + my_bind->buffer_type= MYSQL_TYPE_DOUBLE; + + DIE_UNLESS(my_bind++ < bind_array + bind_count); + my_bind->buffer= malloc(sizeof(double)); + my_bind->buffer_type= MYSQL_TYPE_DOUBLE; + + rc= mysql_stmt_bind_result(stmt, bind_array); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED); + + /*************** Verify truncation results ***************************/ + my_bind= bind_array; + + /* signed tiny -> tiny */ + DIE_UNLESS(*my_bind->error && * (int8*) my_bind->buffer == -10); + + /* signed tiny -> uint32 */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(*my_bind->error && * (int32*) my_bind->buffer == -10); + + /* unsigned tiny -> tiny */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(*my_bind->error && * (uint8*) my_bind->buffer == 200); + + /* short -> ushort */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(*my_bind->error && * (int16*) my_bind->buffer == -32767); + + /* ushort -> short */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(*my_bind->error && * (uint16*) my_bind->buffer == 64000); + + /* short -> ushort (no truncation, data is in the range of target type) */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(! *my_bind->error && * (uint16*) my_bind->buffer == 32000); + + /* ushort -> utiny */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(*my_bind->error && * (int8*) my_bind->buffer == 0); + + /* int -> float: no truncation, the number is a power of two */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(! *my_bind->error && * (float*) my_bind->buffer == 1073741824); + + /* int -> float: truncation, not enough bits in float */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(*my_bind->error); + + /* int -> double: no truncation */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(! *my_bind->error && * (double*) my_bind->buffer == 1073741825); + + /* double -> longlong: fractional part is lost */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + + /* double -> ulonglong, negative fp number to unsigned integer */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + /* Value in the buffer is not defined: don't test it */ + DIE_UNLESS(*my_bind->error); + + /* double -> longlong, negative fp number to signed integer: no loss */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(! *my_bind->error && * (longlong*) my_bind->buffer == -12345678910LL); + + /* big numeric string -> number */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(*my_bind->error); + + /* junk string -> number */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(*my_bind->error && *(longlong*) my_bind->buffer == 0); + + /* string with trailing spaces -> number */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(! *my_bind->error && *(longlong*) my_bind->buffer == 12345); + + /* string with trailing spaces -> double */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + DIE_UNLESS(! *my_bind->error && *(double*) my_bind->buffer == 12345.67); + + /* string with trailing junk -> double */ + DIE_UNLESS(my_bind++ < bind_array + bind_count); + /* + XXX: There must be a truncation error: but it's not the way the server + behaves, so let's leave it for now. + */ + DIE_UNLESS(*(double*) my_bind->buffer == 12345.67); + /* + TODO: string -> double, double -> time, double -> string (truncation + errors are not supported here yet) + longlong -> time/date/datetime + date -> time, date -> timestamp, date -> number + time -> string, time -> date, time -> timestamp, + number -> date string -> date + */ + /*************** Cleanup *********************************************/ + + mysql_stmt_close(stmt); + + for (my_bind= bind_array; my_bind < bind_array + bind_count; my_bind++) + free(my_bind->buffer); + free(bind_array); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + +static void test_truncation_option() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + int rc; + uint8 buf; + my_bool option= 0; + my_bool error; + MYSQL_BIND my_bind; + + myheader("test_truncation_option"); + + /* Prepare the test table */ + stmt_text= "select -1"; + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero((char*) &my_bind, sizeof(my_bind)); + + my_bind.buffer= (void*) &buf; + my_bind.buffer_type= MYSQL_TYPE_TINY; + my_bind.is_unsigned= TRUE; + my_bind.error= &error; + + rc= mysql_stmt_bind_result(stmt, &my_bind); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED); + DIE_UNLESS(error); + rc= mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, (char*) &option); + myquery(rc); + /* need to rebind for the new setting to take effect */ + rc= mysql_stmt_bind_result(stmt, &my_bind); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + /* The only change is rc - error pointers are still filled in */ + DIE_UNLESS(error == 1); + /* restore back the defaults */ + option= 1; + mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, (char*) &option); + + mysql_stmt_close(stmt); +} + + +/* Bug#6761 - mysql_list_fields doesn't work */ + +static void test_bug6761(void) +{ + const char *stmt_text; + MYSQL_RES *res; + int rc; + myheader("test_bug6761"); + + stmt_text= "CREATE TABLE t1 (a int, b char(255), c decimal)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + res= mysql_list_fields(mysql, "t1", "%"); + DIE_UNLESS(res && mysql_num_fields(res) == 3); + mysql_free_result(res); + + stmt_text= "DROP TABLE t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + +/* Bug#8330 - mysql_stmt_execute crashes (libmysql) */ + +static void test_bug8330() +{ + const char *stmt_text; + MYSQL_STMT *stmt[2]; + int i, rc; + const char *query= "select a,b from t1 where a=?"; + MYSQL_BIND my_bind[2]; + long lval[2]; + + myheader("test_bug8330"); + + stmt_text= "drop table if exists t1"; + /* in case some previos test failed */ + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "create table t1 (a int, b int)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + bzero((char*) my_bind, sizeof(my_bind)); + for (i=0; i < 2; i++) + { + stmt[i]= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt[i], query, strlen(query)); + check_execute(stmt[i], rc); + + my_bind[i].buffer_type= MYSQL_TYPE_LONG; + lval[i]= 0; + my_bind[i].buffer= (void*) &lval[i]; + my_bind[i].is_null= 0; + mysql_stmt_bind_param(stmt[i], &my_bind[i]); + } + + rc= mysql_stmt_execute(stmt[0]); + check_execute(stmt[0], rc); + + rc= mysql_stmt_execute(stmt[1]); + DIE_UNLESS(rc && mysql_stmt_errno(stmt[1]) == CR_COMMANDS_OUT_OF_SYNC); + rc= mysql_stmt_execute(stmt[0]); + check_execute(stmt[0], rc); + + mysql_stmt_close(stmt[0]); + mysql_stmt_close(stmt[1]); + + stmt_text= "drop table t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + +/* Bug#7990 - mysql_stmt_close doesn't reset mysql->net.last_error */ + +static void test_bug7990() +{ + MYSQL_STMT *stmt; + int rc; + myheader("test_bug7990"); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, "foo", 3); + /* + XXX: the fact that we store errno both in STMT and in + MYSQL is not documented and is subject to change in 5.0 + */ + DIE_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql)); + mysql_stmt_close(stmt); + DIE_UNLESS(!mysql_errno(mysql)); +} + +/* + Bug #15518 - Reusing a stmt that has failed during prepare + does not clear error +*/ + +static void test_bug15518() +{ + MYSQL_STMT *stmt; + MYSQL* mysql1; + int rc; + myheader("test_bug15518"); + + mysql1= mysql_client_init(NULL); + + if (!mysql_real_connect(mysql1, opt_host, opt_user, opt_password, + opt_db ? opt_db : "test", opt_port, opt_unix_socket, + CLIENT_MULTI_STATEMENTS)) + { + fprintf(stderr, "Failed to connect to the database\n"); + DIE_UNLESS(0); + } + + stmt= mysql_stmt_init(mysql1); + + /* + The prepare of foo should fail with errno 1064 since + it's not a valid query + */ + rc= mysql_stmt_prepare(stmt, "foo", 3); + if (!opt_silent) + fprintf(stdout, "rc: %d, mysql_stmt_errno: %d, mysql_errno: %d\n", + rc, mysql_stmt_errno(stmt), mysql_errno(mysql1)); + DIE_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql1)); + + /* + Use the same stmt and reprepare with another query that + suceeds + */ + rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12); + if (!opt_silent) + fprintf(stdout, "rc: %d, mysql_stmt_errno: %d, mysql_errno: %d\n", + rc, mysql_stmt_errno(stmt), mysql_errno(mysql1)); + DIE_UNLESS(!rc || mysql_stmt_errno(stmt) || mysql_errno(mysql1)); + + mysql_stmt_close(stmt); + DIE_UNLESS(!mysql_errno(mysql1)); + + /* + part2, when connection to server has been closed + after first prepare + */ + stmt= mysql_stmt_init(mysql1); + rc= mysql_stmt_prepare(stmt, "foo", 3); + if (!opt_silent) + fprintf(stdout, "rc: %d, mysql_stmt_errno: %d, mysql_errno: %d\n", + rc, mysql_stmt_errno(stmt), mysql_errno(mysql1)); + DIE_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql1)); + + /* Close connection to server */ + mysql_close(mysql1); + + /* + Use the same stmt and reprepare with another query that + suceeds. The prepare should fail with error 2013 since + connection to server has been closed. + */ + rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12); + if (!opt_silent) + fprintf(stdout, "rc: %d, mysql_stmt_errno: %d\n", + rc, mysql_stmt_errno(stmt)); + DIE_UNLESS(rc && mysql_stmt_errno(stmt)); + + mysql_stmt_close(stmt); +} + + +static void disable_query_logs() +{ + int rc; + rc= mysql_query(mysql, "set @@global.general_log=off"); + myquery(rc); + rc= mysql_query(mysql, "set @@global.slow_query_log=off"); + myquery(rc); +} + + +static void enable_query_logs(int truncate) +{ + int rc; + + rc= mysql_query(mysql, "set @save_global_general_log=@@global.general_log"); + myquery(rc); + + rc= mysql_query(mysql, "set @save_global_slow_query_log=@@global.slow_query_log"); + myquery(rc); + + rc= mysql_query(mysql, "set @@global.general_log=on"); + myquery(rc); + + rc= mysql_query(mysql, "set @@global.slow_query_log=on"); + myquery(rc); + + + if (truncate) + { + rc= mysql_query(mysql, "truncate mysql.general_log"); + myquery(rc); + + rc= mysql_query(mysql, "truncate mysql.slow_log"); + myquery(rc); + } +} + + +static void restore_query_logs() +{ + int rc; + rc= mysql_query(mysql, "set @@global.general_log=@save_global_general_log"); + myquery(rc); + + rc= mysql_query(mysql, "set @@global.slow_query_log=@save_global_slow_query_log"); + myquery(rc); +} + + +static void test_view_sp_list_fields() +{ + int rc; + MYSQL_RES *res; + + myheader("test_view_sp_list_fields"); + + rc= mysql_query(mysql, "DROP FUNCTION IF EXISTS f1"); + myquery(rc); + rc= mysql_query(mysql, "DROP TABLE IF EXISTS v1, t1, t2"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1, t1, t2"); + myquery(rc); + rc= mysql_query(mysql, "create function f1 () returns int return 5"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (s1 char,s2 char)"); + myquery(rc); + rc= mysql_query(mysql, "create table t2 (s1 int);"); + myquery(rc); + rc= mysql_query(mysql, "create view v1 as select s2,sum(s1) - \ +count(s2) as vx from t1 group by s2 having sum(s1) - count(s2) < (select f1() \ +from t2);"); + myquery(rc); + res= mysql_list_fields(mysql, "v1", NullS); + DIE_UNLESS(res != 0 && mysql_num_fields(res) != 0); + rc= mysql_query(mysql, "DROP FUNCTION f1"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW v1"); + myquery(rc); + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + mysql_free_result(res); + myquery(rc); + +} + + +/* + Test mysql_real_escape_string() with gbk charset + + The important part is that 0x27 (') is the second-byte in a invalid + two-byte GBK character here. But 0xbf5c is a valid GBK character, so + it needs to be escaped as 0x5cbf27 +*/ +#define TEST_BUG8378_IN "\xef\xbb\xbf\x27\xbf\x10" +#define TEST_BUG8378_OUT "\xef\xbb\x5c\xbf\x5c\x27\x5c\xbf\x10" + +static void test_bug8378() +{ +#if defined(HAVE_CHARSET_gbk) && !defined(EMBEDDED_LIBRARY) + MYSQL *lmysql; + char out[9]; /* strlen(TEST_BUG8378)*2+1 */ + char buf[256]; + int len, rc; + + myheader("test_bug8378"); + + if (!opt_silent) + fprintf(stdout, "\n Establishing a test connection ..."); + if (!(lmysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + exit(1); + } + if (mysql_options(lmysql, MYSQL_SET_CHARSET_NAME, "gbk")) + { + myerror("mysql_options() failed"); + exit(1); + } + if (!(mysql_real_connect(lmysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + exit(1); + } + if (!opt_silent) + fprintf(stdout, "OK"); + + rc= mysql_query(lmysql, "SET SQL_MODE=''"); + myquery(rc); + + len= mysql_real_escape_string(lmysql, out, TEST_BUG8378_IN, 4); + + /* No escaping should have actually happened. */ + DIE_UNLESS(memcmp(out, TEST_BUG8378_OUT, len) == 0); + + sprintf(buf, "SELECT '%s'", out); + + rc=mysql_real_query(lmysql, buf, strlen(buf)); + myquery(rc); + + mysql_close(lmysql); +#endif +} + + +static void test_bug8722() +{ + MYSQL_STMT *stmt; + int rc; + const char *stmt_text; + + myheader("test_bug8722"); + /* Prepare test data */ + stmt_text= "drop table if exists t1, v1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "CREATE TABLE t1 (c1 varchar(10), c2 varchar(10), c3 varchar(10)," + " c4 varchar(10), c5 varchar(10), c6 varchar(10)," + " c7 varchar(10), c8 varchar(10), c9 varchar(10)," + "c10 varchar(10))"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "INSERT INTO t1 VALUES (1,2,3,4,5,6,7,8,9,10)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "CREATE VIEW v1 AS SELECT * FROM t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + /* Note: if you uncomment following block everything works fine */ +/* + rc= mysql_query(mysql, "sellect * from v1"); + myquery(rc); + mysql_free_result(mysql_store_result(mysql)); +*/ + + stmt= mysql_stmt_init(mysql); + stmt_text= "select * from v1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + mysql_stmt_close(stmt); + stmt_text= "drop table if exists t1, v1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + +MYSQL_STMT *open_cursor(const char *query) +{ + int rc; + const ulong type= (ulong)CURSOR_TYPE_READ_ONLY; + + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); + return stmt; +} + + +static void test_bug8880() +{ + MYSQL_STMT *stmt_list[2], **stmt; + MYSQL_STMT **stmt_list_end= (MYSQL_STMT**) stmt_list + 2; + int rc; + + myheader("test_bug8880"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (a int not null primary key, b int)"); + rc= mysql_query(mysql, "insert into t1 values (1,1)"); + myquery(rc); /* one check is enough */ + /* + when inserting 2 rows everything works well + mysql_query(mysql, "INSERT INTO t1 VALUES (1,1),(2,2)"); + */ + for (stmt= stmt_list; stmt < stmt_list_end; stmt++) + *stmt= open_cursor("select a from t1"); + for (stmt= stmt_list; stmt < stmt_list_end; stmt++) + { + rc= mysql_stmt_execute(*stmt); + check_execute(*stmt, rc); + } + for (stmt= stmt_list; stmt < stmt_list_end; stmt++) + mysql_stmt_close(*stmt); +} + +/* + Test executing a query with prepared statements while query cache is active +*/ + +static void test_open_cursor_prepared_statement_query_cache() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_RES *result; + + myheader("test_open_cursor_prepared_statement_query_cache"); + if (! is_query_cache_available()) + { + fprintf(stdout, "Skipping test_open_cursor_prepared_statement_query_cache: Query cache not available.\n"); + return; + } + + rc= mysql_query(mysql, + "set @save_query_cache_type=" + "@@global.query_cache_type," + "@save_query_cache_size=" + "@@global.query_cache_size"); + myquery(rc); + rc= mysql_query(mysql, "set global query_cache_type=ON"); + myquery(rc); + rc= mysql_query(mysql, "set local query_cache_type=ON"); + myquery(rc); + rc= mysql_query(mysql, "set global query_cache_size=1000000"); + myquery(rc); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (a int not null primary key, b int)"); + rc= mysql_query(mysql, "insert into t1 values (1,1)"); + myquery(rc); /* one check is enough */ + + /* Store query in query cache */ + rc= mysql_query(mysql, "SELECT * FROM t1"); + myquery(rc); + result= mysql_store_result(mysql); + mytest(result); + (void) my_process_result_set(result); + mysql_free_result(result); + + /* Test using a cursor */ + stmt= open_cursor("select a from t1"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "set global query_cache_type=@save_query_cache_type"); + myquery(rc); + rc= mysql_query(mysql, "set global query_cache_size=@save_query_cache_size"); + myquery(rc); +} + + +static void test_bug9159() +{ + MYSQL_STMT *stmt; + int rc; + const char *stmt_text= "select a, b from t1"; + const unsigned long type= CURSOR_TYPE_READ_ONLY; + + myheader("test_bug9159"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (a int not null primary key, b int)"); + rc= mysql_query(mysql, "insert into t1 values (1,1)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void *)&type); + + mysql_stmt_execute(stmt); + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); +} + + +/* Crash when opening a cursor to a query with DISTICNT and no key */ + +static void test_bug9520() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + char a[6]; + ulong a_len; + int rc, row_count= 0; + + myheader("test_bug9520"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (a char(5), b char(5), c char(5)," + " primary key (a, b, c))"); + rc= mysql_query(mysql, "insert into t1 values ('x', 'y', 'z'), " + " ('a', 'b', 'c'), ('k', 'l', 'm')"); + myquery(rc); + + stmt= open_cursor("select distinct b from t1"); + + /* + Not crashes with: + stmt= open_cursor("select distinct a from t1"); + */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (char*) a; + my_bind[0].buffer_length= sizeof(a); + my_bind[0].length= &a_len; + + mysql_stmt_bind_result(stmt, my_bind); + + while (!(rc= mysql_stmt_fetch(stmt))) + row_count++; + + DIE_UNLESS(rc == MYSQL_NO_DATA); + + if (!opt_silent) + printf("Fetched %d rows\n", row_count); + DBUG_ASSERT(row_count == 3); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* + We can't have more than one cursor open for a prepared statement. + Test re-executions of a PS with cursor; mysql_stmt_reset must close + the cursor attached to the statement, if there is one. +*/ + +static void test_bug9478() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + char a[6]; + ulong a_len; + int rc, i; + DBUG_ENTER("test_bug9478"); + + myheader("test_bug9478"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key, " + " name varchar(20) not null)"); + rc= mysql_query(mysql, "insert into t1 (id, name) values " + " (1, 'aaa'), (2, 'bbb'), (3, 'ccc')"); + myquery(rc); + + stmt= open_cursor("select name from t1 where id=2"); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (char*) a; + my_bind[0].buffer_length= sizeof(a); + my_bind[0].length= &a_len; + mysql_stmt_bind_result(stmt, my_bind); + + for (i= 0; i < 5; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + + /* + The query above is a one-row result set. Therefore, there is no + cursor associated with it, as the server won't bother with opening + a cursor for a one-row result set. The first row was read from the + server in the fetch above. But there is eof packet pending in the + network. mysql_stmt_execute will flush the packet and successfully + execute the statement. + */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + { + char buff[8]; + /* Fill in the fetch packet */ + int4store(buff, stmt->stmt_id); + buff[4]= 1; /* prefetch rows */ + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc); + if (!opt_silent && i == 0) + printf("Got error (as expected): %s\n", mysql_error(mysql)); + } + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + + rc= mysql_stmt_reset(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc && mysql_stmt_errno(stmt)); + if (!opt_silent && i == 0) + printf("Got error (as expected): %s\n", mysql_stmt_error(stmt)); + } + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + /* Test the case with a server side cursor */ + stmt= open_cursor("select name from t1"); + + mysql_stmt_bind_result(stmt, my_bind); + + for (i= 0; i < 5; i++) + { + DBUG_PRINT("loop",("i: %d", i)); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + while (! (rc= mysql_stmt_fetch(stmt))) + { + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + + rc= mysql_stmt_reset(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc && mysql_stmt_errno(stmt)); + if (!opt_silent && i == 0) + printf("Got error (as expected): %s\n", mysql_stmt_error(stmt)); + } + + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + DBUG_VOID_RETURN; +} + + +/* + Error message is returned for unsupported features. + Test also cursors with non-default PREFETCH_ROWS +*/ + +static void test_bug9643() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + int32 a; + int rc; + const char *stmt_text; + int num_rows= 0; + ulong type; + ulong prefetch_rows= 5; + + myheader("test_bug9643"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key)"); + rc= mysql_query(mysql, "insert into t1 (id) values " + " (1), (2), (3), (4), (5), (6), (7), (8), (9)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + /* Not implemented in 5.0 */ + type= (ulong) CURSOR_TYPE_SCROLLABLE; + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_stmt_error(stmt)); + + type= (ulong) CURSOR_TYPE_READ_ONLY; + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); + check_execute(stmt, rc); + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, + (void*) &prefetch_rows); + check_execute(stmt, rc); + stmt_text= "select * from t1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void*) &a; + my_bind[0].buffer_length= sizeof(a); + mysql_stmt_bind_result(stmt, my_bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + while ((rc= mysql_stmt_fetch(stmt)) == 0) + ++num_rows; + DIE_UNLESS(num_rows == 9); + + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + +/* + Bug#11111: fetch from view returns wrong data +*/ + +static void test_bug11111() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + char buf[2][20]; + ulong len[2]; + int i; + int rc; + const char *query= "SELECT DISTINCT f1,ff2 FROM v1"; + + myheader("test_bug11111"); + + rc= mysql_query(mysql, "drop table if exists t1, t2, v1"); + myquery(rc); + rc= mysql_query(mysql, "drop view if exists t1, t2, v1"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (f1 int, f2 int)"); + myquery(rc); + rc= mysql_query(mysql, "create table t2 (ff1 int, ff2 int)"); + myquery(rc); + rc= mysql_query(mysql, "create view v1 as select * from t1, t2 where f1=ff1"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1,1), (2,2), (3,3)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t2 values (1,1), (2,2), (3,3)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + mysql_stmt_prepare(stmt, query, strlen(query)); + mysql_stmt_execute(stmt); + + bzero((char*) my_bind, sizeof(my_bind)); + for (i=0; i < 2; i++) + { + my_bind[i].buffer_type= MYSQL_TYPE_STRING; + my_bind[i].buffer= (uchar* *)&buf[i]; + my_bind[i].buffer_length= 20; + my_bind[i].length= &len[i]; + } + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent) + printf("return: %s", buf[1]); + DIE_UNLESS(!strcmp(buf[1],"1")); + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop view v1"); + myquery(rc); + rc= mysql_query(mysql, "drop table t1, t2"); + myquery(rc); +} + +/* + Check that proper cleanups are done for prepared statement when + fetching thorugh a cursor. +*/ + +static void test_bug10729() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + char a[21]; + int rc; + const char *stmt_text; + int i= 0; + const char *name_array[3]= { "aaa", "bbb", "ccc" }; + ulong type; + + myheader("test_bug10729"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "name VARCHAR(20) NOT NULL)"); + rc= mysql_query(mysql, "insert into t1 (id, name) values " + "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + type= (ulong) CURSOR_TYPE_READ_ONLY; + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); + check_execute(stmt, rc); + stmt_text= "select name from t1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void*) a; + my_bind[0].buffer_length= sizeof(a); + mysql_stmt_bind_result(stmt, my_bind); + + for (i= 0; i < 3; i++) + { + int row_no= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + DIE_UNLESS(strcmp(a, name_array[row_no]) == 0); + if (!opt_silent) + printf("%d: %s\n", row_no, a); + ++row_no; + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + } + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* + Check that mysql_next_result works properly in case when one of + the statements used in a multi-statement query is erroneous +*/ + +static void test_bug9992() +{ + MYSQL *mysql1; + MYSQL_RES* res ; + int rc; + + myheader("test_bug9992"); + + if (!opt_silent) + printf("Establishing a connection with option CLIENT_MULTI_STATEMENTS..\n"); + + mysql1= mysql_client_init(NULL); + + if (!mysql_real_connect(mysql1, opt_host, opt_user, opt_password, + opt_db ? opt_db : "test", opt_port, opt_unix_socket, + CLIENT_MULTI_STATEMENTS)) + { + fprintf(stderr, "Failed to connect to the database\n"); + DIE_UNLESS(0); + } + + + /* Sic: SHOW DATABASE is incorrect syntax. */ + rc= mysql_query(mysql1, "SHOW TABLES; SHOW DATABASE; SELECT 1;"); + + if (rc) + { + fprintf(stderr, "[%d] %s\n", mysql_errno(mysql1), mysql_error(mysql1)); + DIE_UNLESS(0); + } + + if (!opt_silent) + printf("Testing mysql_store_result/mysql_next_result..\n"); + + res= mysql_store_result(mysql1); + DIE_UNLESS(res); + mysql_free_result(res); + rc= mysql_next_result(mysql1); + DIE_UNLESS(rc == 1); /* Got errors, as expected */ + + if (!opt_silent) + fprintf(stdout, "Got error, as expected:\n [%d] %s\n", + mysql_errno(mysql1), mysql_error(mysql1)); + + mysql_close(mysql1); +} + +/* Bug#10736: cursors and subqueries, memroot management */ + +static void test_bug10736() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + char a[21]; + int rc; + const char *stmt_text; + int i= 0; + ulong type; + + myheader("test_bug10736"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "name VARCHAR(20) NOT NULL)"); + rc= mysql_query(mysql, "insert into t1 (id, name) values " + "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + type= (ulong) CURSOR_TYPE_READ_ONLY; + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); + check_execute(stmt, rc); + stmt_text= "select name from t1 where name=(select name from t1 where id=2)"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void*) a; + my_bind[0].buffer_length= sizeof(a); + mysql_stmt_bind_result(stmt, my_bind); + + for (i= 0; i < 3; i++) + { + int row_no= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + printf("%d: %s\n", row_no, a); + ++row_no; + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + } + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + +/* Bug#10794: cursors, packets out of order */ + +static void test_bug10794() +{ + MYSQL_STMT *stmt, *stmt1; + MYSQL_BIND my_bind[2]; + char a[21]; + int id_val; + ulong a_len; + int rc; + const char *stmt_text; + int i= 0; + ulong type; + + myheader("test_bug10794"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "name varchar(20) not null)"); + stmt= mysql_stmt_init(mysql); + stmt_text= "insert into t1 (id, name) values (?, ?)"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void*) &id_val; + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void*) a; + my_bind[1].length= &a_len; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + for (i= 0; i < 42; i++) + { + id_val= (i+1)*10; + sprintf(a, "a%d", i); + a_len= strlen(a); /* safety against broken sprintf */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + stmt_text= "select name from t1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + stmt1= mysql_stmt_init(mysql); + mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void*) a; + my_bind[0].buffer_length= sizeof(a); + my_bind[0].length= &a_len; + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent) + printf("Fetched row from stmt: %s\n", a); + /* Don't optimize: an attribute of the original test case */ + mysql_stmt_free_result(stmt); + mysql_stmt_reset(stmt); + stmt_text= "select name from t1 where id=10"; + rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text)); + check_execute(stmt1, rc); + rc= mysql_stmt_bind_result(stmt1, my_bind); + check_execute(stmt1, rc); + rc= mysql_stmt_execute(stmt1); + while (1) + { + rc= mysql_stmt_fetch(stmt1); + if (rc == MYSQL_NO_DATA) + { + if (!opt_silent) + printf("End of data in stmt1\n"); + break; + } + check_execute(stmt1, rc); + if (!opt_silent) + printf("Fetched row from stmt1: %s\n", a); + } + mysql_stmt_close(stmt); + mysql_stmt_close(stmt1); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* Bug#11172: cursors, crash on a fetch from a datetime column */ + +static void test_bug11172() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind_in[1], bind_out[2]; + MYSQL_TIME hired; + int rc; + const char *stmt_text; + int i= 0, id; + ulong type; + + myheader("test_bug11172"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "hired date not null)"); + rc= mysql_query(mysql, + "insert into t1 (id, hired) values (1, '1933-08-24'), " + "(2, '1965-01-01'), (3, '1949-08-17'), (4, '1945-07-07'), " + "(5, '1941-05-15'), (6, '1978-09-15'), (7, '1936-03-28')"); + myquery(rc); + stmt= mysql_stmt_init(mysql); + stmt_text= "SELECT id, hired FROM t1 WHERE hired=?"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + bzero((char*) bind_in, sizeof(bind_in)); + bzero((char*) bind_out, sizeof(bind_out)); + bzero((char*) &hired, sizeof(hired)); + hired.year= 1965; + hired.month= 1; + hired.day= 1; + bind_in[0].buffer_type= MYSQL_TYPE_DATE; + bind_in[0].buffer= (void*) &hired; + bind_in[0].buffer_length= sizeof(hired); + bind_out[0].buffer_type= MYSQL_TYPE_LONG; + bind_out[0].buffer= (void*) &id; + bind_out[1]= bind_in[0]; + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_bind_param(stmt, bind_in); + check_execute(stmt, rc); + rc= mysql_stmt_bind_result(stmt, bind_out); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + printf("fetched data %d:%d-%d-%d\n", id, + hired.year, hired.month, hired.day); + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + if (!mysql_stmt_free_result(stmt)) + mysql_stmt_reset(stmt); + } + mysql_stmt_close(stmt); + mysql_rollback(mysql); + mysql_rollback(mysql); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* Bug#11656: cursors, crash on a fetch from a query with distinct. */ + +static void test_bug11656() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + int rc; + const char *stmt_text; + char buf[2][20]; + int i= 0; + ulong type; + + myheader("test_bug11656"); + + mysql_query(mysql, "drop table if exists t1"); + + rc= mysql_query(mysql, "create table t1 (" + "server varchar(40) not null, " + "test_kind varchar(1) not null, " + "test_id varchar(30) not null , " + "primary key (server,test_kind,test_id))"); + myquery(rc); + + stmt_text= "select distinct test_kind, test_id from t1 " + "where server in (?, ?)"; + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + bzero((char*) my_bind, sizeof(my_bind)); + strmov(buf[0], "pcint502_MY2"); + strmov(buf[1], "*"); + for (i=0; i < 2; i++) + { + my_bind[i].buffer_type= MYSQL_TYPE_STRING; + my_bind[i].buffer= (uchar* *)&buf[i]; + my_bind[i].buffer_length= strlen(buf[i]); + } + mysql_stmt_bind_param(stmt, my_bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* + Check that the server signals when NO_BACKSLASH_ESCAPES mode is in effect, + and mysql_real_escape_string() does the right thing as a result. +*/ + +static void test_bug10214() +{ + int len; + char out[8]; + + myheader("test_bug10214"); + + DIE_UNLESS(!(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)); + + len= mysql_real_escape_string(mysql, out, "a'b\\c", 5); + DIE_UNLESS(memcmp(out, "a\\'b\\\\c", len) == 0); + + mysql_query(mysql, "set sql_mode='NO_BACKSLASH_ESCAPES'"); + DIE_UNLESS(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES); + + len= mysql_real_escape_string(mysql, out, "a'b\\c", 5); + DIE_UNLESS(memcmp(out, "a''b\\c", len) == 0); + + mysql_query(mysql, "set sql_mode=''"); +} + +static void test_client_character_set() +{ + MY_CHARSET_INFO cs; + char *csname= (char*) "utf8"; + char *csdefault= (char*)mysql_character_set_name(mysql); + int rc; + + myheader("test_client_character_set"); + + rc= mysql_set_character_set(mysql, csname); + DIE_UNLESS(rc == 0); + + mysql_get_character_set_info(mysql, &cs); + DIE_UNLESS(!strcmp(cs.csname, "utf8mb3")); + DIE_UNLESS(!strcmp(cs.name, "utf8mb3_general_ci")); + /* Restore the default character set */ + rc= mysql_set_character_set(mysql, csdefault); + myquery(rc); +} + +/* Test correct max length for MEDIUMTEXT and LONGTEXT columns */ + +static void test_bug9735() +{ + MYSQL_RES *res; + int rc; + + myheader("test_bug9735"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (a mediumtext, b longtext) " + "character set latin1"); + myquery(rc); + rc= mysql_query(mysql, "select * from t1"); + myquery(rc); + res= mysql_store_result(mysql); + verify_prepare_field(res, 0, "a", "a", MYSQL_TYPE_BLOB, + "t1", "t1", current_db, (1U << 24)-1, 0); + verify_prepare_field(res, 1, "b", "b", MYSQL_TYPE_BLOB, + "t1", "t1", current_db, ~0U, 0); + mysql_free_result(res); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* Bug#11183 "mysql_stmt_reset() doesn't reset information about error" */ + +static void test_bug11183() +{ + int rc; + MYSQL_STMT *stmt; + char bug_statement[]= "insert into t1 values (1)"; + + myheader("test_bug11183"); + + mysql_query(mysql, "drop table t1 if exists"); + mysql_query(mysql, "create table t1 (a int)"); + + stmt= mysql_stmt_init(mysql); + DIE_UNLESS(stmt != 0); + + rc= mysql_stmt_prepare(stmt, bug_statement, strlen(bug_statement)); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + + /* Trying to execute statement that should fail on execute stage */ + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc); + + mysql_stmt_reset(stmt); + DIE_UNLESS(mysql_stmt_errno(stmt) == 0); + + mysql_query(mysql, "create table t1 (a int)"); + + /* Trying to execute statement that should pass ok */ + if (mysql_stmt_execute(stmt)) + { + mysql_stmt_reset(stmt); + DIE_UNLESS(mysql_stmt_errno(stmt) == 0); + } + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + +static void test_bug11037() +{ + MYSQL_STMT *stmt; + int rc; + const char *stmt_text; + + myheader("test_bug11037"); + + mysql_query(mysql, "drop table if exists t1"); + + rc= mysql_query(mysql, "create table t1 (id int not null)"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1 values (1)"); + myquery(rc); + + stmt_text= "select id FROM t1"; + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + + /* expected error */ + rc = mysql_stmt_fetch(stmt); + DIE_UNLESS(rc==1); + if (!opt_silent) + fprintf(stdout, "Got error, as expected:\n [%d] %s\n", + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc==0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc==MYSQL_NO_DATA); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc==MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + +/* Bug#10760: cursors, crash in a fetch after rollback. */ + +static void test_bug10760() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + int rc; + const char *stmt_text; + char id_buf[20]; + ulong id_len; + int i= 0; + ulong type; + + myheader("test_bug10760"); + + mysql_query(mysql, "drop table if exists t1, t2"); + + /* create tables */ + rc= mysql_query(mysql, "create table t1 (id integer not null primary key)" + " engine=MyISAM"); + myquery(rc); + for (; i < 42; ++i) + { + char buf[100]; + sprintf(buf, "insert into t1 (id) values (%d)", i+1); + rc= mysql_query(mysql, buf); + myquery(rc); + } + mysql_autocommit(mysql, FALSE); + /* create statement */ + stmt= mysql_stmt_init(mysql); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + /* + 1: check that a deadlock within the same connection + is resolved and an error is returned. The deadlock is modelled + as follows: + con1: open cursor for select * from t1; + con1: insert into t1 (id) values (1) + */ + stmt_text= "select id from t1 order by 1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_query(mysql, "update t1 set id=id+100"); + /* + If cursors are not materialized, the update will return an error; + we mainly test that it won't deadlock. + */ + if (rc && !opt_silent) + printf("Got error (as expected): %s\n", mysql_error(mysql)); + /* + 2: check that MyISAM tables used in cursors survive + COMMIT/ROLLBACK. + */ + rc= mysql_rollback(mysql); /* should not close the cursor */ + myquery(rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + /* + 3: check that cursors to InnoDB tables are closed (for now) by + COMMIT/ROLLBACK. + */ + if (! have_innodb) + { + if (!opt_silent) + printf("Testing that cursors are closed at COMMIT/ROLLBACK requires " + "InnoDB.\n"); + } + else + { + stmt_text= "select id from t1 order by 1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "alter table t1 engine=InnoDB"); + myquery(rc); + + bzero(my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (void*) id_buf; + my_bind[0].buffer_length= sizeof(id_buf); + my_bind[0].length= &id_len; + check_execute(stmt, rc); + mysql_stmt_bind_result(stmt, my_bind); + + rc= mysql_stmt_execute(stmt); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + if (!opt_silent) + printf("Fetched row %s\n", id_buf); + rc= mysql_rollback(mysql); /* should close the cursor */ + myquery(rc); +#if 0 + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc); + if (!opt_silent) + printf("Got error (as expected): %s\n", mysql_error(mysql)); +#endif + } + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + mysql_autocommit(mysql, TRUE); /* restore default */ +} + +static void test_bug12001() +{ + MYSQL *mysql_local; + MYSQL_RES *result; + const char *query= "DROP TABLE IF EXISTS test_table;" + "CREATE TABLE test_table(id INT);" + "INSERT INTO test_table VALUES(10);" + "UPDATE test_table SET id=20 WHERE id=10;" + "SELECT * FROM test_table;" + "INSERT INTO non_existent_table VALUES(11);"; + int rc, res; + + myheader("test_bug12001"); + + if (!(mysql_local= mysql_client_init(NULL))) + { + fprintf(stdout, "\n mysql_client_init() failed"); + exit(1); + } + + /* Create connection that supports multi statements */ + if (!mysql_real_connect(mysql_local, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_STATEMENTS)) + { + fprintf(stdout, "\n mysql_real_connect() failed"); + exit(1); + } + + rc= mysql_query(mysql_local, query); + myquery(rc); + + do + { + if (mysql_field_count(mysql_local) && + (result= mysql_use_result(mysql_local))) + { + mysql_free_result(result); + } + } + while (!(res= mysql_next_result(mysql_local))); + + rc= mysql_query(mysql_local, "DROP TABLE IF EXISTS test_table"); + myquery(rc); + + mysql_close(mysql_local); + DIE_UNLESS(res==1); +} + + +/* Bug#11909: wrong metadata if fetching from two cursors */ + +static void test_bug11909() +{ + MYSQL_STMT *stmt1, *stmt2; + MYSQL_BIND my_bind[7]; + int rc; + char firstname[20], midinit[20], lastname[20], workdept[20]; + ulong firstname_len, midinit_len, lastname_len, workdept_len; + uint32 empno; + double salary; + float bonus; + const char *stmt_text; + + myheader("test_bug11909"); + + stmt_text= "drop table if exists t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create table t1 (" + " empno int(11) not null, firstname varchar(20) not null," + " midinit varchar(20) not null, lastname varchar(20) not null," + " workdept varchar(6) not null, salary double not null," + " bonus float not null, primary key (empno)" + ") default charset=latin1 collate=latin1_bin"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "insert into t1 values " + "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000), " + "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800)," + "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800)," + "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), " + "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + /* ****** Begin of trace ****** */ + + stmt1= open_cursor("SELECT empno, firstname, midinit, lastname," + "workdept, salary, bonus FROM t1"); + + bzero(my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void*) &empno; + + my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + my_bind[1].buffer= (void*) firstname; + my_bind[1].buffer_length= sizeof(firstname); + my_bind[1].length= &firstname_len; + + my_bind[2].buffer_type= MYSQL_TYPE_VAR_STRING; + my_bind[2].buffer= (void*) midinit; + my_bind[2].buffer_length= sizeof(midinit); + my_bind[2].length= &midinit_len; + + my_bind[3].buffer_type= MYSQL_TYPE_VAR_STRING; + my_bind[3].buffer= (void*) lastname; + my_bind[3].buffer_length= sizeof(lastname); + my_bind[3].length= &lastname_len; + + my_bind[4].buffer_type= MYSQL_TYPE_VAR_STRING; + my_bind[4].buffer= (void*) workdept; + my_bind[4].buffer_length= sizeof(workdept); + my_bind[4].length= &workdept_len; + + my_bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + my_bind[5].buffer= (void*) &salary; + + my_bind[6].buffer_type= MYSQL_TYPE_FLOAT; + my_bind[6].buffer= (void*) &bonus; + rc= mysql_stmt_bind_result(stmt1, my_bind); + check_execute(stmt1, rc); + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_fetch(stmt1); + DIE_UNLESS(rc == 0); + DIE_UNLESS(empno == 10); + DIE_UNLESS(strcmp(firstname, "CHRISTINE") == 0); + DIE_UNLESS(strcmp(midinit, "I") == 0); + DIE_UNLESS(strcmp(lastname, "HAAS") == 0); + DIE_UNLESS(strcmp(workdept, "A00") == 0); + DIE_UNLESS(salary == (double) 52750.0); + DIE_UNLESS(bonus == (float) 1000.0); + + stmt2= open_cursor("SELECT empno, firstname FROM t1"); + rc= mysql_stmt_bind_result(stmt2, my_bind); + check_execute(stmt2, rc); + + rc= mysql_stmt_execute(stmt2); + check_execute(stmt2, rc); + + rc= mysql_stmt_fetch(stmt2); + DIE_UNLESS(rc == 0); + + DIE_UNLESS(empno == 10); + DIE_UNLESS(strcmp(firstname, "CHRISTINE") == 0); + + rc= mysql_stmt_reset(stmt2); + check_execute(stmt2, rc); + + /* ERROR: next statement should return 0 */ + + rc= mysql_stmt_fetch(stmt1); + DIE_UNLESS(rc == 0); + + mysql_stmt_close(stmt1); + mysql_stmt_close(stmt2); + rc= mysql_rollback(mysql); + myquery(rc); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + +/* Cursors: opening a cursor to a compilicated query with ORDER BY */ + +static void test_bug11901() +{ + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[2]; + int rc; + char workdept[20]; + ulong workdept_len; + uint32 empno; + const char *stmt_text; + + myheader("test_bug11901"); + + stmt_text= "drop table if exists t1, t2"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create table t1 (" + " empno int(11) not null, firstname varchar(20) not null," + " midinit varchar(20) not null, lastname varchar(20) not null," + " workdept varchar(6) not null, salary double not null," + " bonus float not null, primary key (empno), " + " unique key (workdept, empno) " + ") default charset=latin1 collate=latin1_bin"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "insert into t1 values " + "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000)," + "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800), " + "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800), " + "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), " + "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500), " + "(70, 'EVA', 'D', 'PULASKI', 'D21', 36170, 700), " + "(90, 'EILEEN', 'W', 'HENDERSON', 'E11', 29750, 600), " + "(100, 'THEODORE', 'Q', 'SPENSER', 'E21', 26150, 500), " + "(110, 'VINCENZO', 'G', 'LUCCHESSI', 'A00', 46500, 900), " + "(120, 'SEAN', '', 'O\\'CONNELL', 'A00', 29250, 600), " + "(130, 'DOLORES', 'M', 'QUINTANA', 'C01', 23800, 500), " + "(140, 'HEATHER', 'A', 'NICHOLLS', 'C01', 28420, 600), " + "(150, 'BRUCE', '', 'ADAMSON', 'D11', 25280, 500), " + "(160, 'ELIZABETH', 'R', 'PIANKA', 'D11', 22250, 400), " + "(170, 'MASATOSHI', 'J', 'YOSHIMURA', 'D11', 24680, 500), " + "(180, 'MARILYN', 'S', 'SCOUTTEN', 'D11', 21340, 500), " + "(190, 'JAMES', 'H', 'WALKER', 'D11', 20450, 400), " + "(200, 'DAVID', '', 'BROWN', 'D11', 27740, 600), " + "(210, 'WILLIAM', 'T', 'JONES', 'D11', 18270, 400), " + "(220, 'JENNIFER', 'K', 'LUTZ', 'D11', 29840, 600), " + "(230, 'JAMES', 'J', 'JEFFERSON', 'D21', 22180, 400), " + "(240, 'SALVATORE', 'M', 'MARINO', 'D21', 28760, 600), " + "(250, 'DANIEL', 'S', 'SMITH', 'D21', 19180, 400), " + "(260, 'SYBIL', 'P', 'JOHNSON', 'D21', 17250, 300), " + "(270, 'MARIA', 'L', 'PEREZ', 'D21', 27380, 500), " + "(280, 'ETHEL', 'R', 'SCHNEIDER', 'E11', 26250, 500), " + "(290, 'JOHN', 'R', 'PARKER', 'E11', 15340, 300), " + "(300, 'PHILIP', 'X', 'SMITH', 'E11', 17750, 400), " + "(310, 'MAUDE', 'F', 'SETRIGHT', 'E11', 15900, 300), " + "(320, 'RAMLAL', 'V', 'MEHTA', 'E21', 19950, 400), " + "(330, 'WING', '', 'LEE', 'E21', 25370, 500), " + "(340, 'JASON', 'R', 'GOUNOT', 'E21', 23840, 500)"; + + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create table t2 (" + " deptno varchar(6) not null, deptname varchar(20) not null," + " mgrno int(11) not null, location varchar(20) not null," + " admrdept varchar(6) not null, refcntd int(11) not null," + " refcntu int(11) not null, primary key (deptno)" + ") default charset=latin1 collate=latin1_bin"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "insert into t2 values " + "('A00', 'SPIFFY COMPUTER SERV', 10, '', 'A00', 0, 0), " + "('B01', 'PLANNING', 20, '', 'A00', 0, 0), " + "('C01', 'INFORMATION CENTER', 30, '', 'A00', 0, 0), " + "('D01', 'DEVELOPMENT CENTER', 0, '', 'A00', 0, 0)," + "('D11', 'MANUFACTURING SYSTEM', 60, '', 'D01', 0, 0), " + "('D21', 'ADMINISTRATION SYSTE', 70, '', 'D01', 0, 0), " + "('E01', 'SUPPORT SERVICES', 50, '', 'A00', 0, 0), " + "('E11', 'OPERATIONS', 90, '', 'E01', 0, 0), " + "('E21', 'SOFTWARE SUPPORT', 100,'', 'E01', 0, 0)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + /* ****** Begin of trace ****** */ + + stmt= open_cursor("select t1.empno, t1.workdept " + "from (t1 left join t2 on t2.deptno = t1.workdept) " + "where t2.deptno in " + " (select t2.deptno " + " from (t1 left join t2 on t2.deptno = t1.workdept) " + " where t1.empno = ?) " + "order by 1"); + bzero(my_bind, sizeof(my_bind)); + + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= &empno; + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + my_bind[1].buffer= (void*) workdept; + my_bind[1].buffer_length= sizeof(workdept); + my_bind[1].length= &workdept_len; + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + empno= 10; + /* ERROR: next statement causes a server crash */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1, t2"); + myquery(rc); +} + +/* Bug#11904: mysql_stmt_attr_set CURSOR_TYPE_READ_ONLY grouping wrong result */ + +static void test_bug11904() +{ + MYSQL_STMT *stmt1; + int rc; + const char *stmt_text; + const ulong type= (ulong)CURSOR_TYPE_READ_ONLY; + MYSQL_BIND my_bind[2]; + int country_id=0; + char row_data[11]= {0}; + + myheader("test_bug11904"); + + /* create tables */ + rc= mysql_query(mysql, "DROP TABLE IF EXISTS bug11904b"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE bug11904b (id int, name char(10), primary key(id, name))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO bug11904b VALUES (1, 'sofia'), (1,'plovdiv')," + " (1,'varna'), (2,'LA'), (2,'new york'), (3,'heidelberg')," + " (3,'berlin'), (3, 'frankfurt')"); + + myquery(rc); + mysql_commit(mysql); + /* create statement */ + stmt1= mysql_stmt_init(mysql); + mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + stmt_text= "SELECT id, MIN(name) FROM bug11904b GROUP BY id"; + + rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text)); + check_execute(stmt1, rc); + + memset(my_bind, 0, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer=& country_id; + my_bind[0].buffer_length= 0; + my_bind[0].length= 0; + + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer=& row_data; + my_bind[1].buffer_length= sizeof(row_data) - 1; + my_bind[1].length= 0; + + rc= mysql_stmt_bind_result(stmt1, my_bind); + check_execute(stmt1, rc); + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + DIE_UNLESS(country_id == 1); + DIE_UNLESS(memcmp(row_data, "plovdiv", 7) == 0); + + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + DIE_UNLESS(country_id == 2); + DIE_UNLESS(memcmp(row_data, "LA", 2) == 0); + + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + DIE_UNLESS(country_id == 3); + DIE_UNLESS(memcmp(row_data, "berlin", 6) == 0); + + rc= mysql_stmt_close(stmt1); + check_execute(stmt1, rc); + + rc= mysql_query(mysql, "drop table bug11904b"); + myquery(rc); +} + + +/* Bug#12243: multiple cursors, crash in a fetch after commit. */ + +static void test_bug12243() +{ + MYSQL_STMT *stmt1, *stmt2; + int rc; + const char *stmt_text; + ulong type; + + myheader("test_bug12243"); + + if (! have_innodb) + { + if (!opt_silent) + printf("This test requires InnoDB.\n"); + return; + } + + /* create tables */ + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (a int) engine=InnoDB"); + rc= mysql_query(mysql, "insert into t1 (a) values (1), (2)"); + myquery(rc); + mysql_autocommit(mysql, FALSE); + /* create statement */ + stmt1= mysql_stmt_init(mysql); + stmt2= mysql_stmt_init(mysql); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + stmt_text= "select a from t1"; + + rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text)); + check_execute(stmt1, rc); + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_prepare(stmt2, stmt_text, strlen(stmt_text)); + check_execute(stmt2, rc); + rc= mysql_stmt_execute(stmt2); + check_execute(stmt2, rc); + rc= mysql_stmt_fetch(stmt2); + check_execute(stmt2, rc); + + rc= mysql_stmt_close(stmt1); + check_execute(stmt1, rc); + rc= mysql_commit(mysql); + myquery(rc); + rc= mysql_stmt_fetch(stmt2); + check_execute(stmt2, rc); + + mysql_stmt_close(stmt2); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + mysql_autocommit(mysql, TRUE); /* restore default */ +} + + +/* + Bug#11718: query with function, join and order by returns wrong type +*/ + +static void test_bug11718() +{ + MYSQL_RES *res; + int rc; + const char *query= "select str_to_date(concat(f3),'%Y%m%d') from t1,t2 " + "where f1=f2 order by f1"; + + myheader("test_bug11718"); + + rc= mysql_query(mysql, "drop table if exists t1, t2"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (f1 int)"); + myquery(rc); + rc= mysql_query(mysql, "create table t2 (f2 int, f3 numeric(8))"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1), (2)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t2 values (1,20050101), (2,20050202)"); + myquery(rc); + rc= mysql_query(mysql, query); + myquery(rc); + res = mysql_store_result(mysql); + + if (!opt_silent) + printf("return type: %s", (res->fields[0].type == MYSQL_TYPE_DATE)?"DATE": + "not DATE"); + DIE_UNLESS(res->fields[0].type == MYSQL_TYPE_DATE); + mysql_free_result(res); + rc= mysql_query(mysql, "drop table t1, t2"); + myquery(rc); +} + + +/* + Bug #12925: Bad handling of maximum values in getopt +*/ +static void test_bug12925() +{ + myheader("test_bug12925"); + if (opt_getopt_ll_test) + DIE_UNLESS(opt_getopt_ll_test == 25600LL*1024*1024); +} + + +/* + Bug#14210 "Simple query with > operator on large table gives server + crash" +*/ + +static void test_bug14210() +{ + MYSQL_STMT *stmt; + int rc, i; + const char *stmt_text; + ulong type; + + myheader("test_bug14210"); + + mysql_query(mysql, "drop table if exists t1"); + /* + To trigger the problem the table must be InnoDB, although the problem + itself is not InnoDB related. In case the table is MyISAM this test + is harmless. + */ + mysql_query(mysql, "create table t1 (a varchar(255)) engine=InnoDB"); + rc= mysql_query(mysql, "insert into t1 (a) values (repeat('a', 256))"); + myquery(rc); + rc= mysql_query(mysql, "set @@session.max_heap_table_size=16384"); + /* Create a big enough table (more than max_heap_table_size) */ + for (i= 0; i < 8; i++) + { + rc= mysql_query(mysql, "insert into t1 (a) select a from t1"); + myquery(rc); + } + /* create statement */ + stmt= mysql_stmt_init(mysql); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + stmt_text= "select a from t1"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + ; + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + rc= mysql_query(mysql, "set @@session.max_heap_table_size=default"); + myquery(rc); +} + +/* Bug#13488: wrong column metadata when fetching from cursor */ + +static void test_bug13488() +{ + MYSQL_BIND my_bind[3]; + MYSQL_STMT *stmt1; + int rc, f1, f2, f3, i; + const ulong type= CURSOR_TYPE_READ_ONLY; + const char *query= "select * from t1 left join t2 on f1=f2 where f1=1"; + + myheader("test_bug13488"); + + rc= mysql_query(mysql, "drop table if exists t1, t2"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (f1 int not null primary key)"); + myquery(rc); + rc= mysql_query(mysql, "create table t2 (f2 int not null primary key, " + "f3 int not null)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1), (2)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t2 values (1,2), (2,4)"); + myquery(rc); + + memset(my_bind, 0, sizeof(my_bind)); + for (i= 0; i < 3; i++) + { + my_bind[i].buffer_type= MYSQL_TYPE_LONG; + my_bind[i].buffer_length= 4; + my_bind[i].length= 0; + } + my_bind[0].buffer=&f1; + my_bind[1].buffer=&f2; + my_bind[2].buffer=&f3; + + stmt1= mysql_stmt_init(mysql); + rc= mysql_stmt_attr_set(stmt1,STMT_ATTR_CURSOR_TYPE, (const void *)&type); + check_execute(stmt1, rc); + + rc= mysql_stmt_prepare(stmt1, query, strlen(query)); + check_execute(stmt1, rc); + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_bind_result(stmt1, my_bind); + check_execute(stmt1, rc); + + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_free_result(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_reset(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_close(stmt1); + check_execute(stmt1, rc); + + if (!opt_silent) + { + printf("data: f1: %d; f2: %d; f3: %d\n", f1, f2, f3); + printf("data is: %s\n", + (f1 == 1 && f2 == 1 && f3 == 2) ? "OK" : "wrong"); + } + DIE_UNLESS(f1 == 1 && f2 == 1 && f3 == 2); + rc= mysql_query(mysql, "drop table t1, t2"); + myquery(rc); +} + +/* + Bug#13524: warnings of a previous command are not reset when fetching + from a cursor. +*/ + +static void test_bug13524() +{ + MYSQL_STMT *stmt; + int rc; + unsigned int warning_count; + const ulong type= CURSOR_TYPE_READ_ONLY; + const char *query= "select * from t1"; + + myheader("test_bug13524"); + + rc= mysql_query(mysql, "drop table if exists t1, t2"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (a int not null primary key)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1), (2), (3), (4)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + check_execute(stmt, rc); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + warning_count= mysql_warning_count(mysql); + DIE_UNLESS(warning_count == 0); + + /* Check that DROP TABLE produced a warning (no such table) */ + rc= mysql_query(mysql, "drop table if exists t2"); + myquery(rc); + warning_count= mysql_warning_count(mysql); + DIE_UNLESS(warning_count == 1); + + /* + Check that fetch from a cursor cleared the warning from the previous + command. + */ + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + warning_count= mysql_warning_count(mysql); + DIE_UNLESS(warning_count == 0); + + /* Cleanup */ + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + +/* + Bug#14845 "mysql_stmt_fetch returns MYSQL_NO_DATA when COUNT(*) is 0" +*/ + +static void test_bug14845() +{ + MYSQL_STMT *stmt; + int rc; + const ulong type= CURSOR_TYPE_READ_ONLY; + const char *query= "select count(*) from t1 where 1 = 0"; + + myheader("test_bug14845"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (id int(11) default null, " + "name varchar(20) default null)" + "engine=MyISAM DEFAULT CHARSET=utf8"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1,'abc'),(2,'def')"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + check_execute(stmt, rc); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + /* Cleanup */ + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* + Bug #15510: mysql_warning_count returns 0 after mysql_stmt_fetch which + should warn +*/ +static void test_bug15510() +{ + MYSQL_STMT *stmt; + int rc; + const char *query= "select 1 from dual where 1/0"; + + myheader("test_bug15510"); + + rc= mysql_query(mysql, "set @@sql_mode='ERROR_FOR_DIVISION_BY_ZERO'"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(mysql_warning_count(mysql)); + + /* Cleanup */ + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "set @@sql_mode=''"); + myquery(rc); +} + + +/* Test MYSQL_OPT_RECONNECT, Bug#15719 */ + +static void test_opt_reconnect() +{ + MYSQL *lmysql; + + + myheader("test_opt_reconnect"); + + if (!(lmysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + exit(1); + } + + if (!opt_silent) + fprintf(stdout, "reconnect before mysql_options: %d\n", get_reconnect(lmysql)); + DIE_UNLESS(get_reconnect(lmysql) == 0); + + if (mysql_options(lmysql, MYSQL_OPT_RECONNECT, &my_true)) + { + myerror("mysql_options failed: unknown option MYSQL_OPT_RECONNECT\n"); + DIE_UNLESS(0); + } + + /* reconnect should be 1 */ + if (!opt_silent) + fprintf(stdout, "reconnect after mysql_options: %d\n", get_reconnect(lmysql)); + DIE_UNLESS(get_reconnect(lmysql) == 1); + + if (!(mysql_real_connect(lmysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + DIE_UNLESS(0); + } + + /* reconnect should still be 1 */ + if (!opt_silent) + fprintf(stdout, "reconnect after mysql_real_connect: %d\n", + get_reconnect(lmysql)); + DIE_UNLESS(get_reconnect(lmysql) == 1); + + mysql_close(lmysql); + + if (!(lmysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + DIE_UNLESS(0); + } + + if (!opt_silent) + fprintf(stdout, "reconnect before mysql_real_connect: %d\n", get_reconnect(lmysql)); + DIE_UNLESS(get_reconnect(lmysql) == 0); + + if (!(mysql_real_connect(lmysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + DIE_UNLESS(0); + } + + /* reconnect should still be 0 */ + if (!opt_silent) + fprintf(stdout, "reconnect after mysql_real_connect: %d\n", + get_reconnect(lmysql)); + DIE_UNLESS(get_reconnect(lmysql) == 0); + + mysql_close(lmysql); +} + + +#ifndef EMBEDDED_LIBRARY + +static void test_bug12744() +{ + MYSQL_STMT *prep_stmt = NULL; + MYSQL *lmysql; + int rc; + myheader("test_bug12744"); + + lmysql= mysql_client_init(NULL); + DIE_UNLESS(lmysql); + + if (!mysql_real_connect(lmysql, opt_host, opt_user, opt_password, + current_db, opt_port, opt_unix_socket, 0)) + { + fprintf(stderr, "Failed to connect to the database\n"); + DIE_UNLESS(0); + } + + prep_stmt= mysql_stmt_init(lmysql); + rc= mysql_stmt_prepare(prep_stmt, "SELECT 1", 8); + DIE_UNLESS(rc == 0); + + mysql_close(lmysql); + + rc= mysql_stmt_execute(prep_stmt); + DIE_UNLESS(rc); + rc= mysql_stmt_reset(prep_stmt); + DIE_UNLESS(rc); + rc= mysql_stmt_close(prep_stmt); + DIE_UNLESS(rc == 0); +} + +#endif /* EMBEDDED_LIBRARY */ + +/* Bug #16143: mysql_stmt_sqlstate returns an empty string instead of '00000' */ + +static void test_bug16143() +{ + MYSQL_STMT *stmt; + myheader("test_bug16143"); + + stmt= mysql_stmt_init(mysql); + /* Check mysql_stmt_sqlstate return "no error" */ + DIE_UNLESS(strcmp(mysql_stmt_sqlstate(stmt), "00000") == 0); + + mysql_stmt_close(stmt); +} + + +/* Bug #16144: mysql_stmt_attr_get type error */ + +static void test_bug16144() +{ + const my_bool flag_orig= (my_bool) 0xde; + my_bool flag= flag_orig; + MYSQL_STMT *stmt; + myheader("test_bug16144"); + + /* Check that attr_get returns correct data on little and big endian CPUs */ + stmt= mysql_stmt_init(mysql); + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (const void*) &flag); + mysql_stmt_attr_get(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &flag); + DIE_UNLESS(flag == flag_orig); + + mysql_stmt_close(stmt); +} + +/* + Bug #15613: "libmysqlclient API function mysql_stmt_prepare returns wrong + field length" +*/ + +static void test_bug15613() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + MYSQL_RES *metadata; + MYSQL_FIELD *field; + int rc; + myheader("test_bug15613"); + + /* I. Prepare the table */ + rc= mysql_query(mysql, "set names latin1"); + myquery(rc); + mysql_query(mysql, "drop table if exists t1"); + rc= mysql_query(mysql, + "create table t1 (t text character set utf8, " + "tt tinytext character set utf8, " + "mt mediumtext character set utf8, " + "lt longtext character set utf8, " + "vl varchar(255) character set latin1," + "vb varchar(255) character set binary," + "vu varchar(255) character set utf8)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + /* II. Check SELECT metadata */ + stmt_text= ("select t, tt, mt, lt, vl, vb, vu from t1"); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + metadata= mysql_stmt_result_metadata(stmt); + field= mysql_fetch_fields(metadata); + if (!opt_silent) + { + printf("Field lengths (client character set is latin1):\n" + "text character set utf8:\t\t%lu\n" + "tinytext character set utf8:\t\t%lu\n" + "mediumtext character set utf8:\t\t%lu\n" + "longtext character set utf8:\t\t%lu\n" + "varchar(255) character set latin1:\t%lu\n" + "varchar(255) character set binary:\t%lu\n" + "varchar(255) character set utf8:\t%lu\n", + field[0].length, field[1].length, field[2].length, field[3].length, + field[4].length, field[5].length, field[6].length); + } + DIE_UNLESS(field[0].length == 65535); + DIE_UNLESS(field[1].length == 255); + DIE_UNLESS(field[2].length == 16777215); + DIE_UNLESS(field[3].length == 4294967295UL); + DIE_UNLESS(field[4].length == 255); + DIE_UNLESS(field[5].length == 255); + DIE_UNLESS(field[6].length == 255); + mysql_free_result(metadata); + mysql_stmt_free_result(stmt); + + /* III. Cleanup */ + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + rc= mysql_query(mysql, "set names default"); + myquery(rc); + mysql_stmt_close(stmt); +} + +/* + Bug#17667: An attacker has the opportunity to bypass query logging. + + Note! Also tests Bug#21813, where prepared statements are used to + run queries +*/ +static void test_bug17667() +{ + int rc; + MYSQL_STMT *stmt; + enum query_type { QT_NORMAL, QT_PREPARED}; + struct buffer_and_length { + enum query_type qt; + const char *buffer; + const uint length; + } statements[]= { + { QT_NORMAL, "drop table if exists bug17667", 29 }, + { QT_NORMAL, "create table bug17667 (c varchar(20))", 37 }, + { QT_NORMAL, "insert into bug17667 (c) values ('regular') /* NUL=\0 with comment */", 68 }, + { QT_PREPARED, + "insert into bug17667 (c) values ('prepared') /* NUL=\0 with comment */", 69, }, + { QT_NORMAL, "insert into bug17667 (c) values ('NUL=\0 in value')", 50 }, + { QT_NORMAL, "insert into bug17667 (c) values ('5 NULs=\0\0\0\0\0')", 48 }, + { QT_PREPARED, "insert into bug17667 (c) values ('6 NULs=\0\0\0\0\0\0')", 50 }, + { QT_NORMAL, "/* NUL=\0 with comment */ insert into bug17667 (c) values ('encore')", 67 }, + { QT_NORMAL, "drop table bug17667", 19 }, + { QT_NORMAL, NULL, 0 } }; + + struct buffer_and_length *statement_cursor; + FILE *log_file; + char *master_log_filename; + + myheader("test_bug17667"); + + master_log_filename = (char *) malloc(strlen(opt_vardir) + strlen("/log/master.log") + 1); + strxmov(master_log_filename, opt_vardir, "/log/master.log", NullS); + if (!opt_silent) + printf("Opening '%s'\n", master_log_filename); + log_file= my_fopen(master_log_filename, (int) (O_RDONLY | O_BINARY), MYF(0)); + free(master_log_filename); + + if (log_file == NULL) + { + if (!opt_silent) + { + printf("Could not find the log file, VARDIR/log/master.log, so " + "test_bug17667 is not run.\n" + "Run test from the mysql-test/mysql-test-run* program to set up " + "correct environment for this test.\n\n"); + } + return; + } + + enable_query_logs(1); + + for (statement_cursor= statements; statement_cursor->buffer != NULL; + statement_cursor++) + { + if (statement_cursor->qt == QT_NORMAL) + { + /* Run statement as normal query */ + rc= mysql_real_query(mysql, statement_cursor->buffer, + statement_cursor->length); + myquery(rc); + } + else if (statement_cursor->qt == QT_PREPARED) + { + /* + Run as prepared statement + + NOTE! All these queries should be in the log twice, + one time for prepare and one time for execute + */ + stmt= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(stmt, statement_cursor->buffer, + statement_cursor->length); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + } + else + { + DIE_UNLESS(0==1); + } + } + + /* Make sure the server has written the logs to disk before reading it */ + rc= mysql_query(mysql, "flush logs"); + myquery(rc); + + for (statement_cursor= statements; statement_cursor->buffer != NULL; + statement_cursor++) + { + int expected_hits= 1, hits= 0; + char line_buffer[MAX_TEST_QUERY_LENGTH*2]; + /* more than enough room for the query and some marginalia. */ + + /* Prepared statments always occurs twice in log */ + if (statement_cursor->qt == QT_PREPARED) + expected_hits++; + + /* Loop until we found expected number of log entries */ + do { + /* Loop until statement is found in log */ + do { + memset(line_buffer, '/', MAX_TEST_QUERY_LENGTH*2); + + if(fgets(line_buffer, MAX_TEST_QUERY_LENGTH*2, log_file) == NULL) + { + /* If fgets returned NULL, it indicates either error or EOF */ + if (feof(log_file)) + DIE("Found EOF before all statements where found"); + + fprintf(stderr, "Got error %d while reading from file\n", + ferror(log_file)); + DIE("Read error"); + } + + } while (my_memmem(line_buffer, MAX_TEST_QUERY_LENGTH*2, + statement_cursor->buffer, + statement_cursor->length) == NULL); + hits++; + } while (hits < expected_hits); + + if (!opt_silent) + printf("Found statement starting with \"%s\"\n", + statement_cursor->buffer); + } + + restore_query_logs(); + + if (!opt_silent) + printf("success. All queries found intact in the log.\n"); + + my_fclose(log_file, MYF(0)); +} + + +/* + Bug#14169: type of group_concat() result changed to blob if tmp_table was + used +*/ +static void test_bug14169() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + MYSQL_RES *res; + MYSQL_FIELD *field; + int rc; + + myheader("test_bug14169"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + rc= mysql_query(mysql, "set session group_concat_max_len=1024"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (f1 int unsigned, f2 varchar(255))"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1,repeat('a',255))," + "(2,repeat('b',255))"); + myquery(rc); + stmt= mysql_stmt_init(mysql); + stmt_text= "select f2,group_concat(f1) from t1 group by f2"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + myquery(rc); + res= mysql_stmt_result_metadata(stmt); + field= mysql_fetch_fields(res); + if (!opt_silent) + printf("GROUP_CONCAT() result type %i", field[1].type); + DIE_UNLESS(field[1].type == MYSQL_TYPE_BLOB); + mysql_free_result(res); + mysql_stmt_free_result(stmt); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + + rc= mysql_query(mysql, "set session group_concat_max_len=@@global.group_concat_max_len"); + myquery(rc); +} + +/* + Test that mysql_insert_id() behaves as documented in our manual +*/ +static void test_mysql_insert_id() +{ + my_ulonglong res; + int rc; + + myheader("test_mysql_insert_id"); + + rc= mysql_query(mysql, "drop table if exists t1,t2"); + myquery(rc); + /* table without auto_increment column */ + rc= mysql_query(mysql, "create table t1 (f1 int, f2 varchar(255), key(f1))"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1,'a')"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + rc= mysql_query(mysql, "insert into t1 values (null,'b')"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + rc= mysql_query(mysql, "insert into t1 select 5,'c'"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + + /* + Test for bug #34889: mysql_client_test::test_mysql_insert_id test fails + sporadically + */ + rc= mysql_query(mysql, "create table t2 (f1 int not null primary key auto_increment, f2 varchar(255))"); + myquery(rc); + rc= mysql_query(mysql, "insert into t2 values (null,'b')"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 select 5,'c'"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + rc= mysql_query(mysql, "drop table t2"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1 select null,'d'"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + rc= mysql_query(mysql, "insert into t1 values (null,last_insert_id(300))"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 300); + rc= mysql_query(mysql, "insert into t1 select null,last_insert_id(400)"); + myquery(rc); + res= mysql_insert_id(mysql); + /* + Behaviour change: old code used to return 0; but 400 is consistent + with INSERT VALUES, and the manual's section of mysql_insert_id() does not + say INSERT SELECT should be different. + */ + DIE_UNLESS(res == 400); + + /* table with auto_increment column */ + rc= mysql_query(mysql, "create table t2 (f1 int not null primary key auto_increment, f2 varchar(255))"); + myquery(rc); + rc= mysql_query(mysql, "insert into t2 values (1,'a')"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 1); + /* this should not influence next INSERT if it doesn't have auto_inc */ + rc= mysql_query(mysql, "insert into t1 values (10,'e')"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + + rc= mysql_query(mysql, "insert into t2 values (null,'b')"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 2); + rc= mysql_query(mysql, "insert into t2 select 5,'c'"); + myquery(rc); + res= mysql_insert_id(mysql); + /* + Manual says that for multirow insert this should have been 5, but does not + say for INSERT SELECT. This is a behaviour change: old code used to return + 0. We try to be consistent with INSERT VALUES. + */ + DIE_UNLESS(res == 5); + rc= mysql_query(mysql, "insert into t2 select null,'d'"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 6); + /* with more than one row */ + rc= mysql_query(mysql, "insert into t2 values (10,'a'),(11,'b')"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 11); + rc= mysql_query(mysql, "insert into t2 select 12,'a' union select 13,'b'"); + myquery(rc); + res= mysql_insert_id(mysql); + /* + Manual says that for multirow insert this should have been 13, but does + not say for INSERT SELECT. This is a behaviour change: old code used to + return 0. We try to be consistent with INSERT VALUES. + */ + DIE_UNLESS(res == 13); + rc= mysql_query(mysql, "insert into t2 values (null,'a'),(null,'b')"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 14); + rc= mysql_query(mysql, "insert into t2 select null,'a' union select null,'b'"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 16); + rc= mysql_query(mysql, "insert into t2 select 12,'a' union select 13,'b'"); + myquery_r(rc); + rc= mysql_query(mysql, "insert ignore into t2 select 12,'a' union select 13,'b'"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + rc= mysql_query(mysql, "insert into t2 values (12,'a'),(13,'b')"); + myquery_r(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + rc= mysql_query(mysql, "insert ignore into t2 values (12,'a'),(13,'b')"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + /* mixing autogenerated and explicit values */ + rc= mysql_query(mysql, "insert into t2 values (null,'e'),(12,'a'),(13,'b')"); + myquery_r(rc); + rc= mysql_query(mysql, "insert into t2 values (null,'e'),(12,'a'),(13,'b'),(25,'g')"); + myquery_r(rc); + rc= mysql_query(mysql, "insert into t2 values (null,last_insert_id(300))"); + myquery(rc); + res= mysql_insert_id(mysql); + /* + according to the manual, this might be 20 or 300, but it looks like + auto_increment column takes priority over last_insert_id(). + */ + DIE_UNLESS(res == 20); + /* If first autogenerated number fails and 2nd works: */ + rc= mysql_query(mysql, "drop table t2"); + myquery(rc); + rc= mysql_query(mysql, "create table t2 (f1 int not null primary key " + "auto_increment, f2 varchar(255), unique (f2))"); + myquery(rc); + rc= mysql_query(mysql, "insert into t2 values (null,'e')"); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 1); + rc= mysql_query(mysql, "insert ignore into t2 values (null,'e'),(null,'a'),(null,'e')"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 2); + /* If autogenerated fails and explicit works: */ + rc= mysql_query(mysql, "insert ignore into t2 values (null,'e'),(12,'c'),(null,'d')"); + myquery(rc); + res= mysql_insert_id(mysql); + /* + Behaviour change: old code returned 3 (first autogenerated, even if it + fails); we now return first successful autogenerated. + */ + DIE_UNLESS(res == 13); + /* UPDATE may update mysql_insert_id() if it uses LAST_INSERT_ID(#) */ + rc= mysql_query(mysql, "update t2 set f1=14 where f1=12"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + rc= mysql_query(mysql, "update t2 set f1=0 where f1=14"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + rc= mysql_query(mysql, "update t2 set f2=last_insert_id(372) where f1=0"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 372); + /* check that LAST_INSERT_ID() does not update mysql_insert_id(): */ + rc= mysql_query(mysql, "insert into t2 values (null,'g')"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 15); + rc= mysql_query(mysql, "update t2 set f2=(@li:=last_insert_id()) where f1=15"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 0); + /* + Behaviour change: now if ON DUPLICATE KEY UPDATE updates a row, + mysql_insert_id() returns the id of the row, instead of not being + affected. + */ + rc= mysql_query(mysql, "insert into t2 values (null,@li) on duplicate key " + "update f2=concat('we updated ',f2)"); + myquery(rc); + res= mysql_insert_id(mysql); + DIE_UNLESS(res == 15); + + rc= mysql_query(mysql, "drop table t1,t2"); + myquery(rc); +} + +/* + Bug#20152: mysql_stmt_execute() writes to MYSQL_TYPE_DATE buffer +*/ + +static void test_bug20152() +{ + MYSQL_BIND my_bind[1]; + MYSQL_STMT *stmt; + MYSQL_TIME tm; + int rc; + const char *query= "INSERT INTO t1 (f1) VALUES (?)"; + + myheader("test_bug20152"); + + memset(my_bind, 0, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_DATE; + my_bind[0].buffer= (void*)&tm; + + memset(&tm, 0, sizeof tm); + tm.year = 2006; + tm.month = 6; + tm.day = 18; + tm.hour = 14; + tm.minute = 9; + tm.second = 42; + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1 (f1 DATE)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_close(stmt); + check_execute(stmt, rc); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + if (tm.hour == 14 && tm.minute == 9 && tm.second == 42) { + if (!opt_silent) + printf("OK!"); + } else { + printf("[14:09:42] != [%02d:%02d:%02d]\n", tm.hour, tm.minute, tm.second); + DIE_UNLESS(0==1); + } +} + +/* Bug#15752 "Lost connection to MySQL server when calling a SP from C API" */ + +static void test_bug15752() +{ + MYSQL mysql_local; + int rc, i; + const int ITERATION_COUNT= 100; + const char *query= "CALL p1()"; + + myheader("test_bug15752"); + + rc= mysql_query(mysql, "drop procedure if exists p1"); + myquery(rc); + rc= mysql_query(mysql, "create procedure p1() select 1"); + myquery(rc); + + mysql_client_init(&mysql_local); + if (! mysql_real_connect(&mysql_local, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, + CLIENT_MULTI_STATEMENTS)) + { + printf("Unable connect to MariaDB server: %s\n", mysql_error(&mysql_local)); + DIE_UNLESS(0); + } + rc= mysql_real_query(&mysql_local, query, strlen(query)); + myquery(rc); + mysql_free_result(mysql_store_result(&mysql_local)); + + rc= mysql_real_query(&mysql_local, query, strlen(query)); + DIE_UNLESS(rc && mysql_errno(&mysql_local) == CR_COMMANDS_OUT_OF_SYNC); + + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(&mysql_local)); + + /* Check some other commands too */ + + DIE_UNLESS(mysql_next_result(&mysql_local) == 0); + mysql_free_result(mysql_store_result(&mysql_local)); + DIE_UNLESS(mysql_next_result(&mysql_local) == -1); + + /* The second problem is not reproducible: add the test case */ + for (i = 0; i < ITERATION_COUNT; i++) + { + if (mysql_real_query(&mysql_local, query, strlen(query))) + { + printf("\ni=%d %s failed: %s\n", i, query, mysql_error(&mysql_local)); + break; + } + mysql_free_result(mysql_store_result(&mysql_local)); + DIE_UNLESS(mysql_next_result(&mysql_local) == 0); + mysql_free_result(mysql_store_result(&mysql_local)); + DIE_UNLESS(mysql_next_result(&mysql_local) == -1); + + } + mysql_close(&mysql_local); + rc= mysql_query(mysql, "drop procedure p1"); + myquery(rc); +} + +/* + Bug#21206: memory corruption when too many cursors are opened at once + + Memory corruption happens when more than 1024 cursors are open + simultaneously. +*/ +static void test_bug21206() +{ + const size_t cursor_count= 1025; + + const char *create_table[]= + { + "DROP TABLE IF EXISTS t1", + "CREATE TABLE t1 (i INT)", + "INSERT INTO t1 VALUES (1), (2), (3)" + }; + const char *query= "SELECT * FROM t1"; + + Stmt_fetch *fetch_array= + (Stmt_fetch*) calloc(cursor_count, sizeof(Stmt_fetch)); + + Stmt_fetch *fetch; + + DBUG_ENTER("test_bug21206"); + myheader("test_bug21206"); + + fill_tables(create_table, sizeof(create_table) / sizeof(*create_table)); + + for (fetch= fetch_array; fetch < fetch_array + cursor_count; ++fetch) + { + /* Init will exit(1) in case of error */ + stmt_fetch_init(fetch, (uint)(fetch - fetch_array), query); + } + + for (fetch= fetch_array; fetch < fetch_array + cursor_count; ++fetch) + stmt_fetch_close(fetch); + + free(fetch_array); + + DBUG_VOID_RETURN; +} + +/* + Ensure we execute the status code while testing +*/ + +static void test_status() +{ + DBUG_ENTER("test_status"); + myheader("test_status"); + + if (!mysql_stat(mysql)) + { + myerror("mysql_stat failed"); /* purecov: inspected */ + die(__FILE__, __LINE__, "mysql_stat failed"); /* purecov: inspected */ + } + DBUG_VOID_RETURN; +} + +/* + Bug#21726: Incorrect result with multiple invocations of + LAST_INSERT_ID + + Test that client gets updated value of insert_id on UPDATE that uses + LAST_INSERT_ID(expr). + select_query added to test for bug + #26921 Problem in mysql_insert_id() Embedded C API function +*/ +static void test_bug21726() +{ + const char *create_table[]= + { + "DROP TABLE IF EXISTS t1", + "CREATE TABLE t1 (i INT)", + "INSERT INTO t1 VALUES (1)", + }; + const char *update_query= "UPDATE t1 SET i= LAST_INSERT_ID(i + 1)"; + int rc; + my_ulonglong insert_id; + const char *select_query= "SELECT * FROM t1"; + MYSQL_RES *result; + + DBUG_ENTER("test_bug21726"); + myheader("test_bug21726"); + + fill_tables(create_table, sizeof(create_table) / sizeof(*create_table)); + + rc= mysql_query(mysql, update_query); + myquery(rc); + insert_id= mysql_insert_id(mysql); + DIE_UNLESS(insert_id == 2); + + rc= mysql_query(mysql, update_query); + myquery(rc); + insert_id= mysql_insert_id(mysql); + DIE_UNLESS(insert_id == 3); + + rc= mysql_query(mysql, select_query); + myquery(rc); + insert_id= mysql_insert_id(mysql); + DIE_UNLESS(insert_id == 3); + result= mysql_store_result(mysql); + mysql_free_result(result); + + DBUG_VOID_RETURN; +} + + +/* + BUG#23383: mysql_affected_rows() returns different values than + mysql_stmt_affected_rows() + + Test that both mysql_affected_rows() and mysql_stmt_affected_rows() + return -1 on error, 0 when no rows were affected, and (positive) row + count when some rows were affected. +*/ +static void test_bug23383() +{ + const char *insert_query= "INSERT INTO t1 VALUES (1), (2)"; + const char *update_query= "UPDATE t1 SET i= 4 WHERE i = 3"; + MYSQL_STMT *stmt; + my_ulonglong row_count; + int rc; + + DBUG_ENTER("test_bug23383"); + myheader("test_bug23383"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (i INT UNIQUE)"); + myquery(rc); + + rc= mysql_query(mysql, insert_query); + myquery(rc); + row_count= mysql_affected_rows(mysql); + DIE_UNLESS(row_count == 2); + + rc= mysql_query(mysql, insert_query); + DIE_UNLESS(rc != 0); + row_count= mysql_affected_rows(mysql); + DIE_UNLESS(row_count == (my_ulonglong)-1); + + rc= mysql_query(mysql, update_query); + myquery(rc); + row_count= mysql_affected_rows(mysql); + DIE_UNLESS(row_count == 0); + + rc= mysql_query(mysql, "DELETE FROM t1"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + DIE_UNLESS(stmt != 0); + + rc= mysql_stmt_prepare(stmt, insert_query, strlen(insert_query)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + row_count= mysql_stmt_affected_rows(stmt); + DIE_UNLESS(row_count == 2); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc != 0); + row_count= mysql_stmt_affected_rows(stmt); + DIE_UNLESS(row_count == (my_ulonglong)-1); + + rc= mysql_stmt_prepare(stmt, update_query, strlen(update_query)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + row_count= mysql_stmt_affected_rows(stmt); + DIE_UNLESS(row_count == 0); + + rc= mysql_stmt_close(stmt); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + +/* + BUG#21635: MYSQL_FIELD struct's member strings seem to misbehave for + expression cols + + Check that for MIN(), MAX(), COUNT() only MYSQL_FIELD::name is set + to either expression or its alias, and db, org_table, table, + org_name fields are empty strings. +*/ +static void test_bug21635() +{ + const char *expr[]= + { + "MIN(i)", "MIN(i)", + "MIN(i) AS A1", "A1", + "MAX(i)", "MAX(i)", + "MAX(i) AS A2", "A2", + "COUNT(i)", "COUNT(i)", + "COUNT(i) AS A3", "A3", + }; + char query[MAX_TEST_QUERY_LENGTH]; + char *query_end; + MYSQL_RES *result; + MYSQL_FIELD *field; + unsigned int field_count, i, j; + int rc; + + DBUG_ENTER("test_bug21635"); + myheader("test_bug21635"); + + query_end= strxmov(query, "SELECT ", NullS); + for (i= 0; i < sizeof(expr) / sizeof(*expr) / 2; ++i) + query_end= strxmov(query_end, expr[i * 2], ", ", NullS); + query_end= strxmov(query_end - 2, " FROM t1 GROUP BY i", NullS); + DIE_UNLESS(query_end - query < MAX_TEST_QUERY_LENGTH); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1 (i INT)"); + myquery(rc); + /* + We need this loop to ensure correct behavior with both constant and + non-constant tables. + */ + for (j= 0; j < 2 ; j++) + { + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)"); + myquery(rc); + + rc= mysql_real_query(mysql, query, (ulong)(query_end - query)); + myquery(rc); + + result= mysql_use_result(mysql); + DIE_UNLESS(result); + + field_count= mysql_field_count(mysql); + for (i= 0; i < field_count; ++i) + { + field= mysql_fetch_field_direct(result, i); + if (!opt_silent) + if (!opt_silent) + printf("%s -> %s ... ", expr[i * 2], field->name); + fflush(stdout); + DIE_UNLESS(field->db[0] == 0 && field->org_table[0] == 0 && + field->table[0] == 0 && field->org_name[0] == 0); + DIE_UNLESS(strcmp(field->name, expr[i * 2 + 1]) == 0); + if (!opt_silent) + if (!opt_silent) + puts("OK"); + } + + mysql_free_result(result); + } + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + +/* + Bug#24179 "select b into $var" fails with --cursor_protocol" + The failure is correct, check that the returned message is meaningful. +*/ + +static void test_bug24179() +{ + int rc; + MYSQL_STMT *stmt; + + DBUG_ENTER("test_bug24179"); + myheader("test_bug24179"); + + stmt= open_cursor("select 1 into @a"); + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc); + if (!opt_silent) + { + printf("Got error (as expected): %d %s\n", + mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + } + DIE_UNLESS(mysql_stmt_errno(stmt) == 1323); + mysql_stmt_close(stmt); + + DBUG_VOID_RETURN; +} + + +/** + Bug#32265 Server returns different metadata if prepared statement is used +*/ + +static void test_bug32265() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_FIELD *field; + MYSQL_RES *metadata; + + DBUG_ENTER("test_bug32265"); + myheader("test_bug32265"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1 (a INTEGER)"); + myquery(rc); + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)"); + myquery(rc); + rc= mysql_query(mysql, "CREATE VIEW v1 AS SELECT * FROM t1"); + myquery(rc); + + stmt= open_cursor("SELECT * FROM t1"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + metadata= mysql_stmt_result_metadata(stmt); + field= mysql_fetch_field(metadata); + DIE_UNLESS(field); + DIE_UNLESS(strcmp(field->table, "t1") == 0); + DIE_UNLESS(strcmp(field->org_table, "t1") == 0); + DIE_UNLESS(strcmp(field->db, "client_test_db") == 0); + mysql_free_result(metadata); + mysql_stmt_close(stmt); + + stmt= open_cursor("SELECT a '' FROM t1 ``"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + metadata= mysql_stmt_result_metadata(stmt); + field= mysql_fetch_field(metadata); + DIE_UNLESS(strcmp(field->table, "") == 0); + DIE_UNLESS(strcmp(field->org_table, "t1") == 0); + DIE_UNLESS(strcmp(field->db, "client_test_db") == 0); + mysql_free_result(metadata); + mysql_stmt_close(stmt); + + stmt= open_cursor("SELECT a '' FROM t1 ``"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + metadata= mysql_stmt_result_metadata(stmt); + field= mysql_fetch_field(metadata); + DIE_UNLESS(strcmp(field->table, "") == 0); + DIE_UNLESS(strcmp(field->org_table, "t1") == 0); + DIE_UNLESS(strcmp(field->db, "client_test_db") == 0); + mysql_free_result(metadata); + mysql_stmt_close(stmt); + + stmt= open_cursor("SELECT * FROM v1"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + metadata= mysql_stmt_result_metadata(stmt); + field= mysql_fetch_field(metadata); + DIE_UNLESS(strcmp(field->table, "v1") == 0); + DIE_UNLESS(strcmp(field->org_table, "v1") == 0); + DIE_UNLESS(strcmp(field->db, "client_test_db") == 0); + mysql_free_result(metadata); + mysql_stmt_close(stmt); + + stmt= open_cursor("SELECT * FROM v1 /* SIC */ GROUP BY 1"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + metadata= mysql_stmt_result_metadata(stmt); + field= mysql_fetch_field(metadata); + DIE_UNLESS(strcmp(field->table, "v1") == 0); + DIE_UNLESS(strcmp(field->org_table, "v1") == 0); + DIE_UNLESS(strcmp(field->db, "client_test_db") == 0); + mysql_free_result(metadata); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP VIEW v1"); + myquery(rc); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + +/* + Bug#28075 "COM_DEBUG crashes mysqld" +*/ + +static void test_bug28075() +{ + int rc; + + DBUG_ENTER("test_bug28075"); + myheader("test_bug28075"); + + rc= mysql_dump_debug_info(mysql); + DIE_UNLESS(rc == 0); + + rc= mysql_ping(mysql); + DIE_UNLESS(rc == 0); + + DBUG_VOID_RETURN; +} + + +/* + Bug#27876 (SF with cyrillic variable name fails during execution (regression)) +*/ + +static void test_bug27876() +{ + int rc; + MYSQL_RES *result; + + uchar utf8_func[] = + { + 0xd1, 0x84, 0xd1, 0x83, 0xd0, 0xbd, 0xd0, 0xba, + 0xd1, 0x86, 0xd0, 0xb8, 0xd0, 0xb9, 0xd0, 0xba, + 0xd0, 0xb0, + 0x00 + }; + + uchar utf8_param[] = + { + 0xd0, 0xbf, 0xd0, 0xb0, 0xd1, 0x80, 0xd0, 0xb0, + 0xd0, 0xbc, 0xd0, 0xb5, 0xd1, 0x82, 0xd1, 0x8a, + 0xd1, 0x80, 0x5f, 0xd0, 0xb2, 0xd0, 0xb5, 0xd1, + 0x80, 0xd1, 0x81, 0xd0, 0xb8, 0xd1, 0x8f, + 0x00 + }; + + char query[500]; + + DBUG_ENTER("test_bug27876"); + myheader("test_bug27876"); + + rc= mysql_query(mysql, "set names utf8"); + myquery(rc); + + rc= mysql_query(mysql, "select version()"); + myquery(rc); + result= mysql_store_result(mysql); + mytest(result); + mysql_free_result(result); + + sprintf(query, "DROP FUNCTION IF EXISTS %s", (char*) utf8_func); + rc= mysql_query(mysql, query); + myquery(rc); + + sprintf(query, + "CREATE FUNCTION %s( %s VARCHAR(25))" + " RETURNS VARCHAR(25) DETERMINISTIC RETURN %s", + (char*) utf8_func, (char*) utf8_param, (char*) utf8_param); + rc= mysql_query(mysql, query); + myquery(rc); + sprintf(query, "SELECT %s(VERSION())", (char*) utf8_func); + rc= mysql_query(mysql, query); + myquery(rc); + result= mysql_store_result(mysql); + mytest(result); + mysql_free_result(result); + + sprintf(query, "DROP FUNCTION %s", (char*) utf8_func); + rc= mysql_query(mysql, query); + myquery(rc); + + rc= mysql_query(mysql, "set names default"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + +/* + Bug#28505: mysql_affected_rows() returns wrong value if CLIENT_FOUND_ROWS + flag is set. +*/ + +static void test_bug28505() +{ + my_ulonglong res; + + myquery(mysql_query(mysql, "drop table if exists t1")); + myquery(mysql_query(mysql, "create table t1(f1 int primary key)")); + myquery(mysql_query(mysql, "insert into t1 values(1)")); + myquery(mysql_query(mysql, + "insert into t1 values(1) on duplicate key update f1=1")); + res= mysql_affected_rows(mysql); + DIE_UNLESS(!res); + myquery(mysql_query(mysql, "drop table t1")); +} + + +/* + Bug#28934: server crash when receiving malformed com_execute packets +*/ + +static void test_bug28934() +{ + my_bool error= 0; + MYSQL_BIND bind[5]; + MYSQL_STMT *stmt; + int cnt; + + myquery(mysql_query(mysql, "drop table if exists t1")); + myquery(mysql_query(mysql, "create table t1(id int)")); + + myquery(mysql_query(mysql, "insert into t1 values(1),(2),(3),(4),(5)")); + stmt= mysql_simple_prepare(mysql,"select * from t1 where id in(?,?,?,?,?)"); + check_stmt(stmt); + + memset (&bind, 0, sizeof (bind)); + for (cnt= 0; cnt < 5; cnt++) + { + bind[cnt].buffer_type= MYSQL_TYPE_LONG; + bind[cnt].buffer= (char*)&cnt; + bind[cnt].buffer_length= 0; + } + myquery(mysql_stmt_bind_param(stmt, bind)); + + stmt->param_count=2; + error= mysql_stmt_execute(stmt); + DIE_UNLESS(error != 0); + myerror(NULL); + mysql_stmt_close(stmt); + + myquery(mysql_query(mysql, "drop table t1")); +} + +/* + Test mysql_change_user() C API and COM_CHANGE_USER +*/ + +static void test_change_user() +{ + char buff[256]; + const char *user_pw= "mysqltest_pw"; + const char *user_no_pw= "mysqltest_no_pw"; + const char *pw= "password"; + const char *db= "mysqltest_user_test_database"; + int rc; + MYSQL* conn; + MYSQL_RES* res; + DBUG_ENTER("test_change_user"); + myheader("test_change_user"); + + /* Prepare environment */ + sprintf(buff, "drop database if exists %s", db); + rc= mysql_query(mysql, buff); + myquery(rc); + + sprintf(buff, "create database %s", db); + rc= mysql_query(mysql, buff); + myquery(rc); + + rc= mysql_query(mysql, "SET SQL_MODE=''"); + myquery(rc); + + sprintf(buff, + "grant select on %s.* to %s@'%%' identified by '%s'", + db, + user_pw, + pw); + rc= mysql_query(mysql, buff); + myquery(rc); + + sprintf(buff, + "grant select on %s.* to %s@'localhost' identified by '%s'", + db, + user_pw, + pw); + rc= mysql_query(mysql, buff); + myquery(rc); + + sprintf(buff, + "grant select on %s.* to %s@'%%'", + db, + user_no_pw); + rc= mysql_query(mysql, buff); + myquery(rc); + + sprintf(buff, + "grant select on %s.* to %s@'localhost'", + db, + user_no_pw); + rc= mysql_query(mysql, buff); + myquery(rc); + + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + /* Try some combinations */ + rc= mysql_change_user(conn, NULL, NULL, NULL); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + + rc= mysql_change_user(conn, "", NULL, NULL); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, "", "", NULL); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + mysql_close(conn); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_change_user(conn, "", "", ""); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, NULL, "", ""); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + + rc= mysql_change_user(conn, NULL, NULL, ""); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + mysql_close(conn); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_change_user(conn, "", NULL, ""); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, user_pw, NULL, ""); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, user_pw, "", ""); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + mysql_close(conn); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_change_user(conn, user_pw, "", NULL); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, user_pw, NULL, NULL); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, user_pw, "", db); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + mysql_close(conn); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_change_user(conn, user_pw, NULL, db); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, user_pw, pw, db); + myquery(rc); + + rc= mysql_change_user(conn, user_pw, pw, NULL); + myquery(rc); + + rc= mysql_change_user(conn, user_pw, pw, ""); + myquery(rc); + + /* MDEV-14581 : Check that there are no warnings after change user.*/ + rc = mysql_query(conn,"SIGNAL SQLSTATE '01000'"); + myquery(rc); + + rc = mysql_change_user(conn, user_pw, pw, ""); + myquery(rc); + + rc = mysql_query(conn, "SHOW WARNINGS"); + myquery(rc); + res = mysql_store_result(conn); + rc = my_process_result_set(res); + DIE_UNLESS(rc == 0); + mysql_free_result(res); + + rc= mysql_change_user(conn, user_no_pw, pw, db); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, user_no_pw, pw, ""); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + mysql_close(conn); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_change_user(conn, user_no_pw, pw, NULL); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, user_no_pw, "", NULL); + myquery(rc); + + rc= mysql_change_user(conn, user_no_pw, "", ""); + myquery(rc); + + rc= mysql_change_user(conn, user_no_pw, "", db); + myquery(rc); + + rc= mysql_change_user(conn, user_no_pw, NULL, db); + myquery(rc); + + rc= mysql_change_user(conn, "", pw, db); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, "", pw, ""); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + mysql_close(conn); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_change_user(conn, "", pw, NULL); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, NULL, pw, NULL); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, NULL, NULL, db); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + mysql_close(conn); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_change_user(conn, NULL, "", db); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + rc= mysql_change_user(conn, "", "", db); + DIE_UNLESS(rc); + if (! opt_silent) + printf("Got error (as expected): %s\n", mysql_error(conn)); + + /* Cleanup the environment */ + + mysql_change_user(conn, opt_user, opt_password, current_db); + + mysql_close(conn); + + sprintf(buff, "drop database %s", db); + rc= mysql_query(mysql, buff); + myquery(rc); + + sprintf(buff, "drop user %s@'%%'", user_pw); + rc= mysql_query(mysql, buff); + myquery(rc); + + sprintf(buff, "drop user %s@'%%'", user_no_pw); + rc= mysql_query(mysql, buff); + myquery(rc); + + sprintf(buff, "drop user %s@'localhost'", user_pw); + rc= mysql_query(mysql, buff); + myquery(rc); + + sprintf(buff, "drop user %s@'localhost'", user_no_pw); + rc= mysql_query(mysql, buff); + myquery(rc); + + DBUG_VOID_RETURN; +} + +/* + Bug#27592 (stack overrun when storing datetime value using prepared statements) +*/ + +static void test_bug27592() +{ + const int NUM_ITERATIONS= 40; + int i; + int rc; + MYSQL_STMT *stmt= NULL; + MYSQL_BIND bind[1]; + MYSQL_TIME time_val; + + DBUG_ENTER("test_bug27592"); + myheader("test_bug27592"); + + mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + mysql_query(mysql, "CREATE TABLE t1(c2 DATETIME)"); + + stmt= mysql_simple_prepare(mysql, "INSERT INTO t1 VALUES (?)"); + DIE_UNLESS(stmt); + + memset(bind, 0, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_DATETIME; + bind[0].buffer= (char *) &time_val; + bind[0].length= NULL; + + for (i= 0; i < NUM_ITERATIONS; i++) + { + time_val.year= 2007; + time_val.month= 6; + time_val.day= 7; + time_val.hour= 18; + time_val.minute= 41; + time_val.second= 3; + + time_val.second_part=0; + time_val.neg=0; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + + mysql_stmt_close(stmt); + + DBUG_VOID_RETURN; +} + +/* + Bug#29687 mysql_stmt_store_result memory leak in libmysqld +*/ + +static void test_bug29687() +{ + const int NUM_ITERATIONS= 40; + int i; + int rc; + MYSQL_STMT *stmt= NULL; + + DBUG_ENTER("test_bug29687"); + myheader("test_bug29687"); + + stmt= mysql_simple_prepare(mysql, "SELECT 1 FROM dual WHERE 0=2"); + DIE_UNLESS(stmt); + + for (i= 0; i < NUM_ITERATIONS; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_store_result(stmt); + while (mysql_stmt_fetch(stmt)==0); + mysql_stmt_free_result(stmt); + } + + mysql_stmt_close(stmt); + DBUG_VOID_RETURN; +} + + +/* + Bug #29692 Single row inserts can incorrectly report a huge number of + row insertions +*/ + +static void test_bug29692() +{ + MYSQL* conn; + + if (!(conn= mysql_client_init(NULL))) + { + myerror("test_bug29692 init failed"); + exit(1); + } + + if (!(mysql_real_connect(conn, opt_host, opt_user, + opt_password, opt_db ? opt_db:"test", opt_port, + opt_unix_socket, CLIENT_FOUND_ROWS))) + { + myerror("test_bug29692 connection failed"); + mysql_close(mysql); + exit(1); + } + myquery(mysql_query(conn, "drop table if exists t1")); + myquery(mysql_query(conn, "create table t1(f1 int)")); + myquery(mysql_query(conn, "insert into t1 values(1)")); + DIE_UNLESS(1 == mysql_affected_rows(conn)); + myquery(mysql_query(conn, "drop table t1")); + mysql_close(conn); +} + +/** + Bug#29306 Truncated data in MS Access with decimal (3,1) columns in a VIEW +*/ + +static void test_bug29306() +{ + MYSQL_FIELD *field; + int rc; + MYSQL_RES *res; + + DBUG_ENTER("test_bug29306"); + myheader("test_bug29306"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS tab17557"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW IF EXISTS view17557"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE tab17557 (dd decimal (3,1))"); + myquery(rc); + rc= mysql_query(mysql, "CREATE VIEW view17557 as SELECT dd FROM tab17557"); + myquery(rc); + rc= mysql_query(mysql, "INSERT INTO tab17557 VALUES (7.6)"); + myquery(rc); + + /* Checking the view */ + res= mysql_list_fields(mysql, "view17557", NULL); + while ((field= mysql_fetch_field(res))) + { + if (! opt_silent) + { + printf("field name %s\n", field->name); + printf("field table %s\n", field->table); + printf("field decimals %d\n", field->decimals); + if (field->decimals < 1) + printf("Error! No decimals! \n"); + printf("\n\n"); + } + DIE_UNLESS(field->decimals == 1); + } + mysql_free_result(res); + + rc= mysql_query(mysql, "DROP TABLE tab17557"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW view17557"); + myquery(rc); + + DBUG_VOID_RETURN; +} +/* + Bug#30472: libmysql doesn't reset charset, insert_id after succ. + mysql_change_user() call row insertions. +*/ + +static void bug30472_retrieve_charset_info(MYSQL *con, + char *character_set_name, + char *character_set_client, + char *character_set_results, + char *collation_connection) +{ + MYSQL_RES *rs; + MYSQL_ROW row; + + /* Get the cached client character set name. */ + + strcpy(character_set_name, mysql_character_set_name(con)); + + /* Retrieve server character set information. */ + + DIE_IF(mysql_query(con, "SHOW VARIABLES LIKE 'character_set_client'")); + DIE_UNLESS(rs= mysql_store_result(con)); + DIE_UNLESS(row= mysql_fetch_row(rs)); + strcpy(character_set_client, row[1]); + mysql_free_result(rs); + + DIE_IF(mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'")); + DIE_UNLESS(rs= mysql_store_result(con)); + DIE_UNLESS(row= mysql_fetch_row(rs)); + strcpy(character_set_results, row[1]); + mysql_free_result(rs); + + DIE_IF(mysql_query(con, "SHOW VARIABLES LIKE 'collation_connection'")); + DIE_UNLESS(rs= mysql_store_result(con)); + DIE_UNLESS(row= mysql_fetch_row(rs)); + strcpy(collation_connection, row[1]); + mysql_free_result(rs); +} + +static void test_bug30472() +{ + MYSQL con; + + char character_set_name_1[MY_CS_CHARACTER_SET_NAME_SIZE]; + char character_set_client_1[MY_CS_CHARACTER_SET_NAME_SIZE]; + char character_set_results_1[MY_CS_CHARACTER_SET_NAME_SIZE]; + char collation_connnection_1[MY_CS_COLLATION_NAME_SIZE]; + + char character_set_name_2[MY_CS_CHARACTER_SET_NAME_SIZE]; + char character_set_client_2[MY_CS_CHARACTER_SET_NAME_SIZE]; + char character_set_results_2[MY_CS_CHARACTER_SET_NAME_SIZE]; + char collation_connnection_2[MY_CS_COLLATION_NAME_SIZE]; + + char character_set_name_3[MY_CS_CHARACTER_SET_NAME_SIZE]; + char character_set_client_3[MY_CS_CHARACTER_SET_NAME_SIZE]; + char character_set_results_3[MY_CS_CHARACTER_SET_NAME_SIZE]; + char collation_connnection_3[MY_CS_COLLATION_NAME_SIZE]; + + char character_set_name_4[MY_CS_CHARACTER_SET_NAME_SIZE]; + char character_set_client_4[MY_CS_CHARACTER_SET_NAME_SIZE]; + char character_set_results_4[MY_CS_CHARACTER_SET_NAME_SIZE]; + char collation_connnection_4[MY_CS_COLLATION_NAME_SIZE]; + + /* Create a new connection. */ + + DIE_UNLESS(mysql_client_init(&con)); + + DIE_UNLESS(mysql_real_connect(&con, + opt_host, + opt_user, + opt_password, + opt_db ? opt_db : "test", + opt_port, + opt_unix_socket, + CLIENT_FOUND_ROWS)); + + /* Retrieve character set information. */ + + bug30472_retrieve_charset_info(&con, + character_set_name_1, + character_set_client_1, + character_set_results_1, + collation_connnection_1); + + /* Switch client character set. */ + + DIE_IF(mysql_set_character_set(&con, "latin2")); + + /* Retrieve character set information. */ + + bug30472_retrieve_charset_info(&con, + character_set_name_2, + character_set_client_2, + character_set_results_2, + collation_connnection_2); + + /* + Check that + 1) character set has been switched and + 2) new character set is different from the original one. + */ + + DIE_UNLESS(strcmp(character_set_name_2, "latin2") == 0); + DIE_UNLESS(strcmp(character_set_client_2, "latin2") == 0); + DIE_UNLESS(strcmp(character_set_results_2, "latin2") == 0); + DIE_UNLESS(strcmp(collation_connnection_2, "latin2_general_ci") == 0); + + DIE_UNLESS(strcmp(character_set_name_1, character_set_name_2) != 0); + DIE_UNLESS(strcmp(character_set_client_1, character_set_client_2) != 0); + DIE_UNLESS(strcmp(character_set_results_1, character_set_results_2) != 0); + DIE_UNLESS(strcmp(collation_connnection_1, collation_connnection_2) != 0); + + /* Call mysql_change_user() with the same username, password, database. */ + + DIE_IF(mysql_change_user(&con, + opt_user, + opt_password, + opt_db ? opt_db : "test")); + + /* Retrieve character set information. */ + + bug30472_retrieve_charset_info(&con, + character_set_name_3, + character_set_client_3, + character_set_results_3, + collation_connnection_3); + + /* Check that character set information has been reset. */ + + DIE_UNLESS(strcmp(character_set_name_1, character_set_name_3) == 0); + DIE_UNLESS(strcmp(character_set_client_1, character_set_client_3) == 0); + DIE_UNLESS(strcmp(character_set_results_1, character_set_results_3) == 0); + DIE_UNLESS(strcmp(collation_connnection_1, collation_connnection_3) == 0); + + /* Change connection-default character set in the client. */ + + mysql_options(&con, MYSQL_SET_CHARSET_NAME, "utf8"); + + /* + Call mysql_change_user() in order to check that new connection will + have UTF8 character set on the client and on the server. + */ + + DIE_IF(mysql_change_user(&con, + opt_user, + opt_password, + opt_db ? opt_db : "test")); + + /* Retrieve character set information. */ + + bug30472_retrieve_charset_info(&con, + character_set_name_4, + character_set_client_4, + character_set_results_4, + collation_connnection_4); + + /* Check that we have UTF8 on the server and on the client. */ + + DIE_UNLESS(strcmp(character_set_name_4, "utf8mb3") == 0); + DIE_UNLESS(strcmp(character_set_client_4, "utf8mb3") == 0); + DIE_UNLESS(strcmp(character_set_results_4, "utf8mb3") == 0); + DIE_UNLESS(strcmp(collation_connnection_4, "utf8mb3_general_ci") == 0); + + /* That's it. Cleanup. */ + + mysql_close(&con); +} + +static void bug20023_change_user(MYSQL *con) +{ + DIE_IF(mysql_change_user(con, + opt_user, + opt_password, + opt_db ? opt_db : "test")); +} + +static my_bool query_str_variable(MYSQL *con, + const char *var_name, + char *str, + size_t len) +{ + MYSQL_RES *rs; + MYSQL_ROW row; + + char query_buffer[MAX_TEST_QUERY_LENGTH]; + + my_bool is_null; + + my_snprintf(query_buffer, sizeof (query_buffer), + "SELECT %s", var_name); + + DIE_IF(mysql_query(con, query_buffer)); + DIE_UNLESS(rs= mysql_store_result(con)); + DIE_UNLESS(row= mysql_fetch_row(rs)); + + is_null= row[0] == NULL; + + if (!is_null) + my_snprintf(str, len, "%s", row[0]); + + mysql_free_result(rs); + + return is_null; +} + +static my_bool query_int_variable(MYSQL *con, + const char *var_name, + int *var_value) +{ + char str[32]; + my_bool is_null= query_str_variable(con, var_name, str, sizeof(str)); + + if (!is_null) + *var_value= atoi(str); + + return is_null; +} + +static void test_bug20023() +{ + MYSQL con; + + int sql_big_selects_orig= 0; + /* + Type of max_join_size is ha_rows, which might be ulong or off_t + depending on the platform or configure options. Preserve the string + to avoid type overflow pitfalls. + */ + char max_join_size_orig[32]; + + int sql_big_selects_2= 0; + int sql_big_selects_3= 0; + int sql_big_selects_4= 0; + int sql_big_selects_5= 0; + + char query_buffer[MAX_TEST_QUERY_LENGTH]; + + /* Create a new connection. */ + + DIE_UNLESS(mysql_client_init(&con)); + + DIE_UNLESS(mysql_real_connect(&con, + opt_host, + opt_user, + opt_password, + opt_db ? opt_db : "test", + opt_port, + opt_unix_socket, + CLIENT_FOUND_ROWS)); + + /*********************************************************************** + Remember original SQL_BIG_SELECTS, MAX_JOIN_SIZE values. + ***********************************************************************/ + + query_int_variable(&con, + "@@session.sql_big_selects", + &sql_big_selects_orig); + + query_str_variable(&con, + "@@global.max_join_size", + max_join_size_orig, + sizeof(max_join_size_orig)); + + /*********************************************************************** + Test that COM_CHANGE_USER resets the SQL_BIG_SELECTS to the initial value. + ***********************************************************************/ + + /* Issue COM_CHANGE_USER. */ + + bug20023_change_user(&con); + + /* Query SQL_BIG_SELECTS. */ + + query_int_variable(&con, + "@@session.sql_big_selects", + &sql_big_selects_2); + + /* Check that SQL_BIG_SELECTS is reset properly. */ + + DIE_UNLESS(sql_big_selects_orig == sql_big_selects_2); + + /*********************************************************************** + Test that if MAX_JOIN_SIZE set to non-default value, + SQL_BIG_SELECTS will be 0. + ***********************************************************************/ + + /* Set MAX_JOIN_SIZE to some non-default value. */ + + DIE_IF(mysql_query(&con, "SET @@global.max_join_size = 10000")); + DIE_IF(mysql_query(&con, "SET @@session.max_join_size = default")); + + /* Issue COM_CHANGE_USER. */ + + bug20023_change_user(&con); + + /* Query SQL_BIG_SELECTS. */ + + query_int_variable(&con, + "@@session.sql_big_selects", + &sql_big_selects_3); + + /* Check that SQL_BIG_SELECTS is 0. */ + + DIE_UNLESS(sql_big_selects_3 == 0); + + /*********************************************************************** + Test that if MAX_JOIN_SIZE set to default value, + SQL_BIG_SELECTS will be 1. + ***********************************************************************/ + + /* Set MAX_JOIN_SIZE to the default value (2^64-1). */ + + DIE_IF(mysql_query(&con, "SET @@global.max_join_size = cast(-1 as unsigned int)")); + DIE_IF(mysql_query(&con, "SET @@session.max_join_size = default")); + + /* Issue COM_CHANGE_USER. */ + + bug20023_change_user(&con); + + /* Query SQL_BIG_SELECTS. */ + + query_int_variable(&con, + "@@session.sql_big_selects", + &sql_big_selects_4); + + /* Check that SQL_BIG_SELECTS is 1. */ + + DIE_UNLESS(sql_big_selects_4 == 1); + + /*********************************************************************** + Restore MAX_JOIN_SIZE. + Check that SQL_BIG_SELECTS will be the original one. + ***********************************************************************/ + + /* Restore MAX_JOIN_SIZE. */ + + my_snprintf(query_buffer, + sizeof (query_buffer), + "SET @@global.max_join_size = %s", + max_join_size_orig); + + DIE_IF(mysql_query(&con, query_buffer)); + + DIE_IF(mysql_query(&con, "SET @@global.max_join_size = cast(-1 as unsigned int)")); + DIE_IF(mysql_query(&con, "SET @@session.max_join_size = default")); + + /* Issue COM_CHANGE_USER. */ + + bug20023_change_user(&con); + + /* Query SQL_BIG_SELECTS. */ + + query_int_variable(&con, + "@@session.sql_big_selects", + &sql_big_selects_5); + + /* Check that SQL_BIG_SELECTS is 1. */ + + DIE_UNLESS(sql_big_selects_5 == sql_big_selects_orig); + + /*********************************************************************** + That's it. Cleanup. + ***********************************************************************/ + + mysql_close(&con); +} + +static void bug31418_impl() +{ + MYSQL con; + + my_bool is_null; + int rc= 0; + + /* Create a new connection. */ + + DIE_UNLESS(mysql_client_init(&con)); + + DIE_UNLESS(mysql_real_connect(&con, + opt_host, + opt_user, + opt_password, + opt_db ? opt_db : "test", + opt_port, + opt_unix_socket, + CLIENT_FOUND_ROWS)); + + /*********************************************************************** + Check that lock is free: + - IS_FREE_LOCK() should return 1; + - IS_USED_LOCK() should return NULL; + ***********************************************************************/ + + is_null= query_int_variable(&con, + "IS_FREE_LOCK('bug31418')", + &rc); + DIE_UNLESS(!is_null && rc); + + is_null= query_int_variable(&con, + "IS_USED_LOCK('bug31418')", + &rc); + DIE_UNLESS(is_null); + + /*********************************************************************** + Acquire lock and check the lock status (the lock must be in use): + - IS_FREE_LOCK() should return 0; + - IS_USED_LOCK() should return non-zero thread id; + ***********************************************************************/ + + query_int_variable(&con, "GET_LOCK('bug31418', 1)", &rc); + DIE_UNLESS(rc); + + is_null= query_int_variable(&con, + "IS_FREE_LOCK('bug31418')", + &rc); + DIE_UNLESS(!is_null && !rc); + + is_null= query_int_variable(&con, + "IS_USED_LOCK('bug31418')", + &rc); + DIE_UNLESS(!is_null && rc); + + /*********************************************************************** + Issue COM_CHANGE_USER command and check the lock status + (the lock must be free): + - IS_FREE_LOCK() should return 1; + - IS_USED_LOCK() should return NULL; + **********************************************************************/ + + bug20023_change_user(&con); + + is_null= query_int_variable(&con, + "IS_FREE_LOCK('bug31418')", + &rc); + DIE_UNLESS(!is_null && rc); + + is_null= query_int_variable(&con, + "IS_USED_LOCK('bug31418')", + &rc); + DIE_UNLESS(is_null); + + /*********************************************************************** + That's it. Cleanup. + ***********************************************************************/ + + mysql_close(&con); +} + +static void test_bug31418() +{ + /* Run test case for BUG#31418 for three different connections. */ + + bug31418_impl(); + + bug31418_impl(); + + bug31418_impl(); +} + + + +/** + Bug#31669 Buffer overflow in mysql_change_user() +*/ + +#define LARGE_BUFFER_SIZE 2048 +#define OLD_USERNAME_CHAR_LENGTH 16 + +static void test_bug31669() +{ + int rc; + static char buff[LARGE_BUFFER_SIZE+1]; +#ifndef EMBEDDED_LIBRARY + static char user[OLD_USERNAME_CHAR_LENGTH+1]; + static char db[NAME_CHAR_LEN+1]; + static char query[LARGE_BUFFER_SIZE*2]; +#endif + MYSQL* conn; + + DBUG_ENTER("test_bug31669"); + myheader("test_bug31669"); + + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_change_user(conn, NULL, NULL, NULL); + DIE_UNLESS(rc); + + rc= mysql_change_user(conn, "", "", ""); + DIE_UNLESS(rc); + + memset(buff, 'a', sizeof(buff) - 1); + buff[sizeof(buff) - 1]= 0; + + mysql_close(conn); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_change_user(conn, buff, buff, buff); + DIE_UNLESS(rc); + + rc = mysql_change_user(conn, opt_user, opt_password, current_db); + DIE_UNLESS(!rc); + +#ifndef EMBEDDED_LIBRARY + memset(db, 'a', sizeof(db)); + db[NAME_CHAR_LEN]= 0; + strxmov(query, "CREATE DATABASE IF NOT EXISTS ", db, NullS); + rc= mysql_query(conn, query); + myquery(rc); + + memset(user, 'b', sizeof(user)); + user[OLD_USERNAME_CHAR_LENGTH]= 0; + memset(buff, 'c', sizeof(buff)); + buff[LARGE_BUFFER_SIZE]= 0; + strxmov(query, "GRANT ALL PRIVILEGES ON *.* TO '", user, "'@'%' IDENTIFIED BY " + "'", buff, "' WITH GRANT OPTION", NullS); + rc= mysql_query(conn, query); + myquery(rc); + + strxmov(query, "GRANT ALL PRIVILEGES ON *.* TO '", user, "'@'localhost' IDENTIFIED BY " + "'", buff, "' WITH GRANT OPTION", NullS); + rc= mysql_query(conn, query); + myquery(rc); + + rc= mysql_query(conn, "FLUSH PRIVILEGES"); + myquery(rc); + + rc= mysql_change_user(conn, user, buff, db); + DIE_UNLESS(!rc); + + user[OLD_USERNAME_CHAR_LENGTH-1]= 'a'; + rc= mysql_change_user(conn, user, buff, db); + DIE_UNLESS(rc); + + user[OLD_USERNAME_CHAR_LENGTH-1]= 'b'; + buff[LARGE_BUFFER_SIZE-1]= 'd'; + rc= mysql_change_user(conn, user, buff, db); + DIE_UNLESS(rc); + + buff[LARGE_BUFFER_SIZE-1]= 'c'; + db[NAME_CHAR_LEN-1]= 'e'; + rc= mysql_change_user(conn, user, buff, db); + DIE_UNLESS(rc); + + mysql_close(conn); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + db[NAME_CHAR_LEN-1]= 'a'; + rc= mysql_change_user(conn, user, buff, db); + DIE_UNLESS(!rc); + + rc= mysql_change_user(conn, user + 1, buff + 1, db + 1); + DIE_UNLESS(rc); + + rc = mysql_change_user(conn, opt_user, opt_password, current_db); + DIE_UNLESS(!rc); + + strxmov(query, "DROP DATABASE ", db, NullS); + rc= mysql_query(conn, query); + myquery(rc); + + strxmov(query, "DELETE FROM mysql.user WHERE User='", user, "'", NullS); + rc= mysql_query(conn, query); + myquery(rc); + DIE_UNLESS(mysql_affected_rows(conn) == 2); +#endif + + mysql_close(conn); + + DBUG_VOID_RETURN; +} + + +/** + Bug#28386 the general log is incomplete +*/ + +static void test_bug28386() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_RES *result; + MYSQL_ROW row; + MYSQL_BIND bind; + const char hello[]= "hello world!"; + + DBUG_ENTER("test_bug28386"); + myheader("test_bug28386"); + + rc= mysql_query(mysql, "select @@global.log_output"); + myquery(rc); + + result= mysql_store_result(mysql); + DIE_UNLESS(result); + + row= mysql_fetch_row(result); + if (! strstr(row[0], "TABLE")) + { + mysql_free_result(result); + if (! opt_silent) + printf("Skipping the test since logging to tables is not enabled\n"); + /* Log output is not to tables */ + DBUG_VOID_RETURN; + } + mysql_free_result(result); + + enable_query_logs(1); + + stmt= mysql_simple_prepare(mysql, "SELECT ?"); + check_stmt(stmt); + + memset(&bind, 0, sizeof(bind)); + + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer= (void *) hello; + bind.buffer_length= sizeof(hello); + + mysql_stmt_bind_param(stmt, &bind); + mysql_stmt_send_long_data(stmt, 0, hello, sizeof(hello)); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + rc= mysql_stmt_reset(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_close(stmt); + DIE_UNLESS(!rc); + + rc= mysql_query(mysql, "select * from mysql.general_log where " + "command_type='Close stmt' or " + "command_type='Reset stmt' or " + "command_type='Long Data'"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + DIE_UNLESS(mysql_num_rows(result) == 3); + + mysql_free_result(result); + + restore_query_logs(); + + DBUG_VOID_RETURN; +} + + +static void test_wl4166_1() +{ + MYSQL_STMT *stmt; + int int_data; + char str_data[50]; + char tiny_data; + short small_data; + longlong big_data; + float real_data; + double double_data; + ulong length[7]; + my_bool is_null[7]; + MYSQL_BIND my_bind[7]; + int rc; + int i; + + myheader("test_wl4166_1"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS table_4166"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE table_4166(col1 tinyint NOT NULL, " + "col2 varchar(15), col3 int, " + "col4 smallint, col5 bigint, " + "col6 float, col7 double, " + "colX varchar(10) default NULL)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, + "INSERT INTO table_4166(col1, col2, col3, col4, col5, col6, col7) " + "VALUES(?, ?, ?, ?, ?, ?, ?)"); + check_stmt(stmt); + + verify_param_count(stmt, 7); + + bzero(my_bind, sizeof(my_bind)); + /* tinyint */ + my_bind[0].buffer_type= MYSQL_TYPE_TINY; + my_bind[0].buffer= (void *)&tiny_data; + /* string */ + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void *)str_data; + my_bind[1].buffer_length= 1000; /* Max string length */ + /* integer */ + my_bind[2].buffer_type= MYSQL_TYPE_LONG; + my_bind[2].buffer= (void *)&int_data; + /* short */ + my_bind[3].buffer_type= MYSQL_TYPE_SHORT; + my_bind[3].buffer= (void *)&small_data; + /* bigint */ + my_bind[4].buffer_type= MYSQL_TYPE_LONGLONG; + my_bind[4].buffer= (void *)&big_data; + /* float */ + my_bind[5].buffer_type= MYSQL_TYPE_FLOAT; + my_bind[5].buffer= (void *)&real_data; + /* double */ + my_bind[6].buffer_type= MYSQL_TYPE_DOUBLE; + my_bind[6].buffer= (void *)&double_data; + + for (i= 0; i < (int) array_elements(my_bind); i++) + { + my_bind[i].length= &length[i]; + my_bind[i].is_null= &is_null[i]; + is_null[i]= 0; + } + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + int_data= 320; + small_data= 1867; + big_data= 1000; + real_data= 2; + double_data= 6578.001; + + /* now, execute the prepared statement to insert 10 records.. */ + for (tiny_data= 0; tiny_data < 10; tiny_data++) + { + length[1]= sprintf(str_data, "MySQL%d", int_data); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + int_data += 25; + small_data += 10; + big_data += 100; + real_data += 1; + double_data += 10.09; + } + + /* force a re-prepare with some DDL */ + + rc= mysql_query(mysql, + "ALTER TABLE table_4166 change colX colX varchar(20) default NULL"); + myquery(rc); + + /* + execute the prepared statement again, + without changing the types of parameters already bound. + */ + + for (tiny_data= 50; tiny_data < 60; tiny_data++) + { + length[1]= sprintf(str_data, "MySQL%d", int_data); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + int_data += 25; + small_data += 10; + big_data += 100; + real_data += 1; + double_data += 10.09; + } + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE table_4166"); + myquery(rc); +} + + +static void test_wl4166_2() +{ + MYSQL_STMT *stmt; + int c_int; + MYSQL_TIME d_date; + MYSQL_BIND bind_out[2]; + int rc; + + myheader("test_wl4166_2"); + + rc= mysql_query(mysql, "SET SQL_MODE=''"); + myquery(rc); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (c_int int, d_date date)"); + myquery(rc); + rc= mysql_query(mysql, + "insert into t1 (c_int, d_date) values (42, '1948-05-15')"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "select * from t1"); + check_stmt(stmt); + + bzero(bind_out, sizeof(bind_out)); + bind_out[0].buffer_type= MYSQL_TYPE_LONG; + bind_out[0].buffer= (void*) &c_int; + + bind_out[1].buffer_type= MYSQL_TYPE_DATE; + bind_out[1].buffer= (void*) &d_date; + + rc= mysql_stmt_bind_result(stmt, bind_out); + check_execute(stmt, rc); + + /* int -> varchar transition */ + + rc= mysql_query(mysql, + "alter table t1 change column c_int c_int varchar(11)"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(c_int == 42); + DIE_UNLESS(d_date.year == 1948); + DIE_UNLESS(d_date.month == 5); + DIE_UNLESS(d_date.day == 15); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + /* varchar to int retrieval with truncation */ + + rc= mysql_query(mysql, "update t1 set c_int='abcde'"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute_r(stmt, rc); + + DIE_UNLESS(c_int == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + /* alter table and increase the number of columns */ + rc= mysql_query(mysql, "alter table t1 add column d_int int"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute_r(stmt, rc); + + rc= mysql_stmt_reset(stmt); + check_execute(stmt, rc); + + /* decrease the number of columns */ + rc= mysql_query(mysql, "alter table t1 drop d_date, drop d_int"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute_r(stmt, rc); + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/** + Test how warnings generated during assignment of parameters + are (currently not) preserve in case of reprepare. +*/ + +static void test_wl4166_3() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + MYSQL_TIME tm[1]; + + myheader("test_wl4166_3"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 (year datetime)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "insert into t1 (year) values (?)"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_DATETIME; + my_bind[0].buffer= &tm[0]; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + tm[0].year= 10000; + tm[0].month= 1; tm[0].day= 1; + tm[0].hour= 1; tm[0].minute= 1; tm[0].second= 1; + tm[0].second_part= 0; tm[0].neg= 0; + + /* Cause a statement reprepare */ + rc= mysql_query(mysql, "alter table t1 add column c int"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + /* + The warning about data truncation when assigning a parameter is lost. + This is a bug. + */ + my_process_warnings(mysql, 0); + + verify_col_data("t1", "year", "0000-00-00 00:00:00"); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/** + Test that long data parameters, as well as parameters + that were originally in a different character set, are + preserved in case of reprepare. +*/ + +static void test_wl4166_4() +{ + MYSQL_STMT *stmt; + int rc; + const char *stmt_text; + MYSQL_BIND bind_array[2]; + + /* Represented as numbers to keep UTF8 tools from clobbering them. */ + const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5"; + const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3"; + char buf1[16], buf2[16]; + ulong buf1_len, buf2_len; + + myheader("test_wl4166_4"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + /* + Create table with binary columns, set session character set to cp1251, + client character set to koi8, and make sure that there is conversion + on insert and no conversion on select + */ + rc= mysql_query(mysql, + "create table t1 (c1 varbinary(255), c2 varbinary(255))"); + myquery(rc); + rc= mysql_query(mysql, "set character_set_client=koi8r, " + "character_set_connection=cp1251, " + "character_set_results=koi8r"); + myquery(rc); + + bzero((char*) bind_array, sizeof(bind_array)); + + bind_array[0].buffer_type= MYSQL_TYPE_STRING; + + bind_array[1].buffer_type= MYSQL_TYPE_STRING; + bind_array[1].buffer= (void *) koi8; + bind_array[1].buffer_length= strlen(koi8); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + stmt_text= "insert into t1 (c1, c2) values (?, ?)"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + mysql_stmt_bind_param(stmt, bind_array); + + mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8)); + + /* Cause a reprepare at statement execute */ + rc= mysql_query(mysql, "alter table t1 add column d int"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + stmt_text= "select c1, c2 from t1"; + + /* c1 and c2 are binary so no conversion will be done on select */ + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bind_array[0].buffer= buf1; + bind_array[0].buffer_length= sizeof(buf1); + bind_array[0].length= &buf1_len; + + bind_array[1].buffer= buf2; + bind_array[1].buffer_length= sizeof(buf2); + bind_array[1].length= &buf2_len; + + mysql_stmt_bind_result(stmt, bind_array); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(buf1_len == strlen(cp1251)); + DIE_UNLESS(buf2_len == strlen(cp1251)); + DIE_UNLESS(!memcmp(buf1, cp1251, buf1_len)); + DIE_UNLESS(!memcmp(buf2, cp1251, buf1_len)); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + rc= mysql_query(mysql, "set names default"); + myquery(rc); +} + +/** + Bug#36004 mysql_stmt_prepare resets the list of warnings +*/ + +static void test_bug36004() +{ + int rc, warning_count= 0; + MYSQL_STMT *stmt; + + DBUG_ENTER("test_bug36004"); + myheader("test_bug36004"); + + rc= mysql_query(mysql, "drop table if exists inexistant"); + myquery(rc); + + DIE_UNLESS(mysql_warning_count(mysql) == 1); + query_int_variable(mysql, "@@warning_count", &warning_count); + DIE_UNLESS(warning_count); + + stmt= mysql_simple_prepare(mysql, "select 1"); + check_stmt(stmt); + + DIE_UNLESS(mysql_warning_count(mysql) == 0); + query_int_variable(mysql, "@@warning_count", &warning_count); + DIE_UNLESS(warning_count); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(mysql_warning_count(mysql) == 0); + mysql_stmt_close(stmt); + + query_int_variable(mysql, "@@warning_count", &warning_count); + DIE_UNLESS(warning_count); + + stmt= mysql_simple_prepare(mysql, "drop table if exists inexistant"); + check_stmt(stmt); + + query_int_variable(mysql, "@@warning_count", &warning_count); + DIE_UNLESS(warning_count == 0); + mysql_stmt_close(stmt); + + DBUG_VOID_RETURN; +} + +/** + Test that COM_REFRESH issues a implicit commit. +*/ + +static void test_wl4284_1() +{ + int rc; + MYSQL_ROW row; + MYSQL_RES *result; + + DBUG_ENTER("test_wl4284_1"); + myheader("test_wl4284_1"); + + /* set AUTOCOMMIT to OFF */ + rc= mysql_autocommit(mysql, FALSE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS trans"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE trans (a INT) ENGINE= InnoDB"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO trans VALUES(1)"); + myquery(rc); + + rc= mysql_refresh(mysql, REFRESH_GRANT | REFRESH_TABLES); + myquery(rc); + + rc= mysql_rollback(mysql); + myquery(rc); + + rc= mysql_query(mysql, "SELECT * FROM trans"); + myquery(rc); + + result= mysql_use_result(mysql); + mytest(result); + + row= mysql_fetch_row(result); + mytest(row); + + mysql_free_result(result); + + /* set AUTOCOMMIT to ON */ + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE trans"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + +static void test_bug38486(void) +{ + MYSQL_STMT *stmt; + const char *stmt_text; + unsigned long type= CURSOR_TYPE_READ_ONLY; + + DBUG_ENTER("test_bug38486"); + myheader("test_bug38486"); + + stmt= mysql_stmt_init(mysql); + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*)&type); + stmt_text= "CREATE TABLE t1 (a INT)"; + mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + mysql_stmt_execute(stmt); + mysql_stmt_close(stmt); + + stmt= mysql_stmt_init(mysql); + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*)&type); + stmt_text= "INSERT INTO t1 VALUES (1)"; + mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + mysql_stmt_execute(stmt); + mysql_stmt_close(stmt); + + DBUG_VOID_RETURN; +} + + +/** + Bug# 33831 mysql_real_connect() should fail if + given an already connected MYSQL handle. +*/ + +static void test_bug33831(void) +{ + MYSQL *l_mysql; + + DBUG_ENTER("test_bug33831"); + + if (!(l_mysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + DIE_UNLESS(0); + } + if (!(mysql_real_connect(l_mysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + DIE_UNLESS(0); + } + + if (mysql_real_connect(l_mysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0)) + { + myerror("connection should have failed"); + DIE_UNLESS(0); + } + + mysql_close(l_mysql); + + DBUG_VOID_RETURN; +} + + +static void test_bug40365(void) +{ + uint rc, i; + MYSQL_STMT *stmt= 0; + MYSQL_BIND my_bind[2]; + my_bool is_null[2]= {0}; + MYSQL_TIME tm[2]; + + DBUG_ENTER("test_bug40365"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1(c1 DATETIME, \ + c2 DATE)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "INSERT INTO t1 VALUES(?, ?)"); + check_stmt(stmt); + verify_param_count(stmt, 2); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_DATETIME; + my_bind[1].buffer_type= MYSQL_TYPE_DATE; + for (i= 0; i < (int) array_elements(my_bind); i++) + { + my_bind[i].buffer= (void *) &tm[i]; + my_bind[i].is_null= &is_null[i]; + } + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + for (i= 0; i < (int) array_elements(my_bind); i++) + { + tm[i].neg= 0; + tm[i].second_part= 0; + tm[i].year= 2009; + tm[i].month= 2; + tm[i].day= 29; + tm[i].hour= 0; + tm[i].minute= 0; + tm[i].second= 0; + } + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_commit(mysql); + myquery(rc); + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "SELECT * FROM t1"); + check_stmt(stmt); + + rc= mysql_stmt_bind_result(stmt, my_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + if (!opt_silent) + fprintf(stdout, "\n"); + + for (i= 0; i < array_elements(my_bind); i++) + { + if (!opt_silent) + fprintf(stdout, "\ntime[%d]: %02d-%02d-%02d ", + i, tm[i].year, tm[i].month, tm[i].day); + DIE_UNLESS(tm[i].year == 0); + DIE_UNLESS(tm[i].month == 0); + DIE_UNLESS(tm[i].day == 0); + } + mysql_stmt_close(stmt); + rc= mysql_commit(mysql); + myquery(rc); + + DBUG_VOID_RETURN; +} + + +/** + Subtest for Bug#43560. Verifies that a loss of connection on the server side + is handled well by the mysql_stmt_execute() call, i.e., no SIGSEGV due to + a vio socket that is cleared upon closed connection. + + Assumes the presence of the close_conn_after_stmt_execute debug feature in + the server. Verifies that it is connected to a debug server before proceeding + with the test. + */ +static void test_bug43560(void) +{ + MYSQL* conn; + uint rc; + MYSQL_STMT *stmt= 0; + MYSQL_BIND bind; + my_bool is_null= 0; + char buffer[256]; + const uint BUFSIZE= sizeof(buffer); + const char* values[] = {"eins", "zwei", "drei", "viele", NULL}; + const char insert_str[] = "INSERT INTO t1 (c2) VALUES (?)"; + unsigned long length; + const unsigned int drop_db= opt_drop_db; + + DBUG_ENTER("test_bug43560"); + myheader("test_bug43560"); + + /* Make sure we only run against a debug server. */ + if (!strstr(mysql->server_version, "debug")) + { + fprintf(stdout, "Skipping test_bug43560: server not DEBUG version\n"); + DBUG_VOID_RETURN; + } + if (opt_unix_socket) + { + fprintf(stdout, "Skipping test_bug43560: connected via UNIX socket\n"); + DBUG_VOID_RETURN; + } + /* + Set up a separate connection for this test to avoid messing up the + general MYSQL object used in other subtests. Use TCP protocol to avoid + problems with the buffer semantics of AF_UNIX, and turn off auto reconnect. + */ + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_query(conn, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(conn, + "CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 CHAR(10))"); + myquery(rc); + + stmt= mysql_stmt_init(conn); + check_stmt(stmt); + rc= mysql_stmt_prepare(stmt, insert_str, strlen(insert_str)); + check_execute(stmt, rc); + + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer_length= BUFSIZE; + bind.buffer= buffer; + bind.is_null= &is_null; + bind.length= &length; + rc= mysql_stmt_bind_param(stmt, &bind); + check_execute(stmt, rc); + + /* First execute; should succeed. */ + strncpy(buffer, values[0], BUFSIZE); + length= strlen(buffer); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* + Set up the server to close this session's server-side socket after + next execution of prep statement. + */ + rc= mysql_query(conn,"SET SESSION debug='+d,close_conn_after_stmt_execute'"); + myquery(rc); + + /* Second execute; should fail due to socket closed during execution. */ + strncpy(buffer, values[1], BUFSIZE); + length= strlen(buffer); + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc && mysql_stmt_errno(stmt) == CR_SERVER_LOST); + + /* + Third execute; should fail (connection already closed), or SIGSEGV in + case of a Bug#43560 type regression in which case the whole test fails. + */ + strncpy(buffer, values[2], BUFSIZE); + length= strlen(buffer); + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc && (mysql_stmt_errno(stmt) == CR_SERVER_LOST || + mysql_stmt_errno(stmt) == CR_SERVER_GONE_ERROR)); + + opt_drop_db= 0; + client_disconnect(conn); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + opt_drop_db= drop_db; + + DBUG_VOID_RETURN; +} + + +/** + Bug#36326: nested transaction and select +*/ + +static void test_bug36326() +{ + int rc; + + DBUG_ENTER("test_bug36326"); + myheader("test_bug36326"); + + if (! is_query_cache_available()) + { + fprintf(stdout, "Skipping test_bug36326: Query cache not available.\n"); + DBUG_VOID_RETURN; + } + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1 (a INTEGER)"); + myquery(rc); + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)"); + myquery(rc); + rc= mysql_query(mysql, + "set @save_query_cache_type=" + "@@global.query_cache_type," + "@save_query_cache_size=" + "@@global.query_cache_size"); + myquery(rc); + rc= mysql_query(mysql, "SET GLOBAL query_cache_type = 1"); + myquery(rc); + rc= mysql_query(mysql, "SET LOCAL query_cache_type = 1"); + myquery(rc); + rc= mysql_query(mysql, "SET GLOBAL query_cache_size = 1048576"); + myquery(rc); + DIE_UNLESS(!(mysql->server_status & SERVER_STATUS_IN_TRANS)); + DIE_UNLESS(mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + rc= mysql_query(mysql, "BEGIN"); + myquery(rc); + DIE_UNLESS(mysql->server_status & SERVER_STATUS_IN_TRANS); + rc= mysql_query(mysql, "SELECT * FROM t1"); + myquery(rc); + rc= my_process_result(mysql); + DIE_UNLESS(rc == 1); + rc= mysql_rollback(mysql); + myquery(rc); + rc= mysql_query(mysql, "ROLLBACK"); + myquery(rc); + DIE_UNLESS(!(mysql->server_status & SERVER_STATUS_IN_TRANS)); + rc= mysql_query(mysql, "SELECT * FROM t1"); + myquery(rc); + DIE_UNLESS(!(mysql->server_status & SERVER_STATUS_IN_TRANS)); + rc= my_process_result(mysql); + DIE_UNLESS(rc == 1); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + rc= mysql_query(mysql, "SET GLOBAL query_cache_size = @save_query_cache_size"); + rc= mysql_query(mysql, "SET GLOBAL query_cache_type = @save_query_cache_type"); + myquery(rc); + + DBUG_VOID_RETURN; +} + +/** + Bug#41078: With CURSOR_TYPE_READ_ONLY mysql_stmt_fetch() returns short + string value. +*/ + +static void test_bug41078(void) +{ + uint rc; + MYSQL_STMT *stmt= 0; + MYSQL_BIND param, result; + ulong cursor_type= CURSOR_TYPE_READ_ONLY; + ulong len; + char str[64]; + const char param_str[]= "abcdefghijklmn"; + my_bool is_null, error; + + DBUG_ENTER("test_bug41078"); + + rc= mysql_query(mysql, "SET NAMES UTF8"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "SELECT ?"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &cursor_type); + check_execute(stmt, rc); + + bzero(¶m, sizeof(param)); + param.buffer_type= MYSQL_TYPE_STRING; + param.buffer= (void *) param_str; + len= sizeof(param_str) - 1; + param.length= &len; + + rc= mysql_stmt_bind_param(stmt, ¶m); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero(&result, sizeof(result)); + result.buffer_type= MYSQL_TYPE_STRING; + result.buffer= str; + result.buffer_length= sizeof(str); + result.is_null= &is_null; + result.length= &len; + result.error= &error; + + rc= mysql_stmt_bind_result(stmt, &result); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(len == sizeof(param_str) - 1 && !strcmp(str, param_str)); + + mysql_stmt_close(stmt); + + DBUG_VOID_RETURN; +} + +/** + Bug#45010: invalid memory reads during parsing some strange statements +*/ +static void test_bug45010() +{ + int rc; + const char query1[]= "select a.\x80", + query2[]= "describe `table\xef"; + + DBUG_ENTER("test_bug45010"); + myheader("test_bug45010"); + + rc= mysql_query(mysql, "set names utf8"); + myquery(rc); + + /* \x80 (-128) could be used as a index of ident_map. */ + rc= mysql_real_query(mysql, query1, sizeof(query1) - 1); + DIE_UNLESS(rc); + + /* \xef (-17) could be used to skip 3 bytes past the buffer end. */ + rc= mysql_real_query(mysql, query2, sizeof(query2) - 1); + DIE_UNLESS(rc); + + rc= mysql_query(mysql, "set names default"); + myquery(rc); + + DBUG_VOID_RETURN; +} + +/** + Bug#44495: Prepared Statement: + CALL p(<x>) - `thd->protocol == &thd->protocol_text' failed +*/ + +static void test_bug44495() +{ + int rc; + MYSQL con; + MYSQL_STMT *stmt; + + DBUG_ENTER("test_bug44495"); + myheader("test_44495"); + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE PROCEDURE p1(IN arg VARCHAR(25))" + " BEGIN SET @stmt = CONCAT('SELECT \"', arg, '\"');" + " PREPARE ps1 FROM @stmt;" + " EXECUTE ps1;" + " DROP PREPARE ps1;" + "END;"); + myquery(rc); + + DIE_UNLESS(mysql_client_init(&con)); + + DIE_UNLESS(mysql_real_connect(&con, opt_host, opt_user, opt_password, + current_db, opt_port, opt_unix_socket, + CLIENT_MULTI_RESULTS)); + + stmt= mysql_simple_prepare(&con, "CALL p1('abc')"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); + + mysql_close(&con); + + rc= mysql_query(mysql, "DROP PROCEDURE p1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + +static void test_bug53371() +{ + int rc; + MYSQL_RES *result; + + myheader("test_bug53371"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "DROP DATABASE IF EXISTS bug53371"); + myquery(rc); + rc= mysql_query(mysql, "DROP USER 'testbug'@localhost"); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)"); + myquery(rc); + rc= mysql_query(mysql, "CREATE DATABASE bug53371"); + myquery(rc); + rc= mysql_query(mysql, "GRANT SELECT ON bug53371.* to 'testbug'@localhost"); + myquery(rc); + + rc= mysql_change_user(mysql, "testbug", NULL, "bug53371"); + myquery(rc); + + rc= mysql_query(mysql, "SHOW COLUMNS FROM client_test_db.t1"); + DIE_UNLESS(rc); + DIE_UNLESS(mysql_errno(mysql) == 1142); + + result= mysql_list_fields(mysql, "../client_test_db/t1", NULL); + DIE_IF(result); + + result= mysql_list_fields(mysql, "#mysql50#/../client_test_db/t1", NULL); + DIE_IF(result); + + rc= mysql_change_user(mysql, opt_user, opt_password, current_db); + myquery(rc); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + rc= mysql_query(mysql, "DROP DATABASE bug53371"); + myquery(rc); + rc= mysql_query(mysql, "DROP USER 'testbug'@localhost"); + myquery(rc); +} + + + +/** + Bug#42373: libmysql can mess a connection at connect +*/ +static void test_bug42373() +{ + int rc; + MYSQL con; + MYSQL_STMT *stmt; + + DBUG_ENTER("test_bug42373"); + myheader("test_42373"); + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE PROCEDURE p1()" + " BEGIN" + " SELECT 1;" + " INSERT INTO t1 VALUES (2);" + "END;"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)"); + myquery(rc); + + /* Try with a stored procedure. */ + DIE_UNLESS(mysql_client_init(&con)); + + mysql_options(&con, MYSQL_INIT_COMMAND, "CALL p1()"); + + DIE_UNLESS(mysql_real_connect(&con, opt_host, opt_user, opt_password, + current_db, opt_port, opt_unix_socket, + CLIENT_MULTI_STATEMENTS|CLIENT_MULTI_RESULTS)); + + stmt= mysql_simple_prepare(&con, "SELECT a FROM t1"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 1); + + mysql_stmt_close(stmt); + mysql_close(&con); + + /* Now try with a multi-statement. */ + DIE_UNLESS(mysql_client_init(&con)); + + mysql_options(&con, MYSQL_INIT_COMMAND, + "SELECT 3; INSERT INTO t1 VALUES (4)"); + + DIE_UNLESS(mysql_real_connect(&con, opt_host, opt_user, opt_password, + current_db, opt_port, opt_unix_socket, + CLIENT_MULTI_STATEMENTS|CLIENT_MULTI_RESULTS)); + + stmt= mysql_simple_prepare(&con, "SELECT a FROM t1"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= my_process_stmt_result(stmt); + DIE_UNLESS(rc == 2); + + mysql_stmt_close(stmt); + mysql_close(&con); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP PROCEDURE p1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + +/** + Bug#54041: MySQL 5.0.92 fails when tests from Connector/C suite run +*/ + +static void test_bug54041_impl() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_BIND bind; + + DBUG_ENTER("test_bug54041"); + myheader("test_bug54041"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "SELECT a FROM t1 WHERE a > ?"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + memset(&bind, 0, sizeof(bind)); + + /* Any type that does not support long data handling. */ + bind.buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, &bind); + check_execute(stmt, rc); + + /* + Trick the client API into sending a long data packet for + the parameter. Long data is only supported for string and + binary types. + */ + stmt->params[0].buffer_type= MYSQL_TYPE_STRING; + + rc= mysql_stmt_send_long_data(stmt, 0, "data", 5); + check_execute(stmt, rc); + + /* Undo API violation. */ + stmt->params[0].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_execute(stmt); + /* Incorrect arguments. */ + check_execute_r(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + +/** + Bug#54041: MySQL 5.0.92 fails when tests from Connector/C suite run +*/ + +static void test_bug54041() +{ + enable_query_logs(0); + test_bug54041_impl(); + disable_query_logs(); + test_bug54041_impl(); + restore_query_logs(); +} + + +/** + Bug#47485: mysql_store_result returns a result set for a prepared statement +*/ +static void test_bug47485() +{ + MYSQL_STMT *stmt; + MYSQL_RES *res; + MYSQL_BIND bind[2]; + int rc; + const char* sql_select = "SELECT 1, 'a'"; + int int_data; + char str_data[16]; + my_bool is_null[2]; + my_bool error[2]; + unsigned long length[2]; + + DBUG_ENTER("test_bug47485"); + myheader("test_bug47485"); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + rc= mysql_stmt_prepare(stmt, sql_select, strlen(sql_select)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + res = mysql_store_result(mysql); + DIE_UNLESS(res == NULL); + + mysql_stmt_reset(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + res = mysql_use_result(mysql); + DIE_UNLESS(res == NULL); + + mysql_stmt_reset(stmt); + + memset(bind, 0, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (char *)&int_data; + bind[0].is_null= &is_null[0]; + bind[0].length= &length[0]; + bind[0].error= &error[0]; + + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (char *)str_data; + bind[1].buffer_length= sizeof(str_data); + bind[1].is_null= &is_null[1]; + bind[1].length= &length[1]; + bind[1].error= &error[1]; + + rc= mysql_stmt_bind_result(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + while (!(rc= mysql_stmt_fetch(stmt))) + ; + + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_reset(stmt); + + memset(bind, 0, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (char *)&int_data; + bind[0].is_null= &is_null[0]; + bind[0].length= &length[0]; + bind[0].error= &error[0]; + + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (char *)str_data; + bind[1].buffer_length= sizeof(str_data); + bind[1].is_null= &is_null[1]; + bind[1].length= &length[1]; + bind[1].error= &error[1]; + + rc= mysql_stmt_bind_result(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + while (!(rc= mysql_stmt_fetch(stmt))) + ; + + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + + DBUG_VOID_RETURN; +} + + +/* + Bug#58036 client utf32, utf16, ucs2 should be disallowed, they crash server +*/ +static void test_bug58036() +{ + MYSQL *conn; + DBUG_ENTER("test_bug58036"); + myheader("test_bug58036"); + + /* Part1: try to connect with ucs2 client character set */ + conn= mysql_client_init(NULL); + mysql_options(conn, MYSQL_SET_CHARSET_NAME, "ucs2"); + + if (mysql_real_connect(conn, opt_host, opt_user, + opt_password, opt_db ? opt_db : "test", + opt_port, opt_unix_socket, 0)) + { + if (!opt_silent) + printf("mysql_real_connect() succeeded (failure expected)\n"); + mysql_close(conn); + DIE(""); + } + + if (!opt_silent) + printf("Got mysql_real_connect() error (expected): %s (%d)\n", + mysql_error(conn), mysql_errno(conn)); + DIE_UNLESS(mysql_errno(conn) == ER_WRONG_VALUE_FOR_VAR || + mysql_errno(conn)== CR_CANT_READ_CHARSET); + mysql_close(conn); + + + /* + Part2: + - connect with latin1 + - then change client character set to ucs2 + - then try mysql_change_user() + */ + conn= mysql_client_init(NULL); + mysql_options(conn, MYSQL_SET_CHARSET_NAME, "latin1"); + if (!mysql_real_connect(conn, opt_host, opt_user, + opt_password, opt_db ? opt_db : "test", + opt_port, opt_unix_socket, 0)) + { + if (!opt_silent) + printf("mysql_real_connect() failed: %s (%d)\n", + mysql_error(conn), mysql_errno(conn)); + mysql_close(conn); + DIE(""); + } + + mysql_options(conn, MYSQL_SET_CHARSET_NAME, "ucs2"); + if (!mysql_change_user(conn, opt_user, opt_password, NULL)) + { + if (!opt_silent) + printf("mysql_change_user() succeeded, error expected!"); + mysql_close(conn); + DIE(""); + } + + if (!opt_silent) + printf("Got mysql_change_user() error (expected): %s (%d)\n", + mysql_error(conn), mysql_errno(conn)); + mysql_close(conn); + DBUG_VOID_RETURN; +} + + +/* + Bug#49972: Crash in prepared statements. + + The following case lead to a server crash: + - Use binary protocol; + - Prepare a statement with OUT-parameter; + - Execute the statement; + - Cause re-prepare of the statement (change dependencies); + - Execute the statement again -- crash here. +*/ + +static void test_bug49972() +{ + int rc; + MYSQL_STMT *stmt; + + MYSQL_BIND in_param_bind; + MYSQL_BIND out_param_bind; + int int_data; + my_bool is_null; + + DBUG_ENTER("test_bug49972"); + myheader("test_bug49972"); + + rc= mysql_query(mysql, "DROP FUNCTION IF EXISTS f1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE FUNCTION f1() RETURNS INT RETURN 1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE PROCEDURE p1(IN a INT, OUT b INT) SET b = a"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "CALL p1((SELECT f1()), ?)"); + check_stmt(stmt); + + bzero((char *) &in_param_bind, sizeof (in_param_bind)); + + in_param_bind.buffer_type= MYSQL_TYPE_LONG; + in_param_bind.buffer= (char *) &int_data; + int_data= 0; + in_param_bind.length= 0; + in_param_bind.is_null= 0; + + rc= mysql_stmt_bind_param(stmt, &in_param_bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + { + bzero(&out_param_bind, sizeof (out_param_bind)); + + out_param_bind.buffer_type= MYSQL_TYPE_LONG; + out_param_bind.is_null= &is_null; + out_param_bind.buffer= &int_data; + out_param_bind.buffer_length= sizeof (int_data); + + rc= mysql_stmt_bind_result(stmt, &out_param_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + rc= mysql_stmt_fetch(stmt); + DBUG_ASSERT(rc == MYSQL_NO_DATA); + + mysql_stmt_next_result(stmt); + mysql_stmt_fetch(stmt); + } + + rc= mysql_query(mysql, "DROP FUNCTION f1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE FUNCTION f1() RETURNS INT RETURN 1"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + { + bzero(&out_param_bind, sizeof (out_param_bind)); + + out_param_bind.buffer_type= MYSQL_TYPE_LONG; + out_param_bind.is_null= &is_null; + out_param_bind.buffer= &int_data; + out_param_bind.buffer_length= sizeof (int_data); + + rc= mysql_stmt_bind_result(stmt, &out_param_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + rc= mysql_stmt_fetch(stmt); + DBUG_ASSERT(rc == MYSQL_NO_DATA); + + mysql_stmt_next_result(stmt); + mysql_stmt_fetch(stmt); + } + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP PROCEDURE p1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP FUNCTION f1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + +/* + Bug #56976: Severe Denial Of Service in prepared statements +*/ +static void test_bug56976() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + int rc; + const char* query = "SELECT LENGTH(?)"; + char *long_buffer; + unsigned long i, packet_len = 256 * 1024L; + unsigned long dos_len = 35000000; + + DBUG_ENTER("test_bug56976"); + myheader("test_bug56976"); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + memset(bind, 0, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_TINY_BLOB; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + long_buffer= (char*) my_malloc(PSI_NOT_INSTRUMENTED, packet_len, MYF(0)); + DIE_UNLESS(long_buffer); + + memset(long_buffer, 'a', packet_len); + + for (i= 0; i < dos_len / packet_len; i++) + { + rc= mysql_stmt_send_long_data(stmt, 0, long_buffer, packet_len); + check_execute(stmt, rc); + } + + my_free(long_buffer); + rc= mysql_stmt_execute(stmt); + + DIE_UNLESS(rc && mysql_stmt_errno(stmt) == ER_UNKNOWN_ERROR); + + mysql_stmt_close(stmt); + + DBUG_VOID_RETURN; +} + +/* + Test that CLIENT_PROGRESS works. +*/ + +uint progress_stage, progress_max_stage, progress_count; + +static void report_progress(const MYSQL *mysql __attribute__((unused)), + uint stage, uint max_stage, + double progress __attribute__((unused)), + const char *proc_info __attribute__((unused)), + uint proc_info_length __attribute__((unused))) +{ + progress_stage= stage; + progress_max_stage= max_stage; + progress_count++; +} + + +static void test_progress_reporting() +{ + int rc, i; + MYSQL* conn; + + /* Progress reporting doesn't work yet with embedded server */ + if (embedded_server_arg_count) + return; + + myheader("test_progress_reporting"); + + + conn= client_connect(CLIENT_PROGRESS_OBSOLETE, MYSQL_PROTOCOL_TCP, 0); + DIE_UNLESS(conn->client_flag & CLIENT_PROGRESS_OBSOLETE); + + mysql_options(conn, MYSQL_PROGRESS_CALLBACK, (void*) report_progress); + rc= mysql_query(conn, "set @save=@@global.progress_report_time"); + myquery(rc); + rc= mysql_query(conn, "set @@global.progress_report_time=1"); + myquery(rc); + + rc= mysql_query(conn, "drop table if exists t1,t2"); + myquery(rc); + rc= mysql_query(conn, "create table t1 (f2 varchar(255)) engine=aria"); + myquery(rc); + rc= mysql_query(conn, "create table t2 like t1"); + myquery(rc); + rc= mysql_query(conn, "insert into t1 (f2) values (repeat('a',100)),(repeat('b',200)),(repeat('c',202)),(repeat('d',202)),(repeat('e',202)),(repeat('f',202)),(repeat('g',23))"); + myquery(rc); + for (i= 0 ; i < 5 ; i++) + { + rc= mysql_query(conn, "insert into t2 (f2) select f2 from t1"); + myquery(rc); + rc= mysql_query(conn, "insert into t1 (f2) select f2 from t2"); + myquery(rc); + } + + progress_stage= progress_max_stage= progress_count= 0; + rc= mysql_query(conn, "alter table t1 add f1 int primary key auto_increment, order by f2"); + myquery(rc); + if (!opt_silent) + printf("Got progress_count: %u stage: %u max_stage: %u\n", + progress_count, progress_stage, progress_max_stage); + DIE_UNLESS(progress_count > 0 && progress_stage >=2 && progress_max_stage == 3); + + progress_stage= progress_max_stage= progress_count= 0; + rc= mysql_query(conn, "create index f2 on t1 (f2)"); + myquery(rc); + if (!opt_silent) + printf("Got progress_count: %u stage: %u max_stage: %u\n", + progress_count, progress_stage, progress_max_stage); + DIE_UNLESS(progress_count > 0 && progress_stage >=2 && progress_max_stage == 2); + + progress_stage= progress_max_stage= progress_count= 0; + rc= mysql_query(conn, "drop index f2 on t1"); + myquery(rc); + if (!opt_silent) + printf("Got progress_count: %u stage: %u max_stage: %u\n", + progress_count, progress_stage, progress_max_stage); + DIE_UNLESS(progress_count > 0 && progress_stage >=2 && progress_max_stage == 2); + + rc= mysql_query(conn, "set @@global.progress_report_time=@save"); + myquery(rc); + mysql_close(conn); +} + +/** + MDEV-3885 - connection suicide via mysql_kill() causes assertion in server +*/ + +static void test_mdev3885() +{ + int rc; + MYSQL *conn; + + myheader("test_mdev3885"); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + rc= mysql_kill(conn, mysql_thread_id(conn)); + DIE_UNLESS(rc); + mysql_close(conn); +} + + +/** + Bug#57058 SERVER_QUERY_WAS_SLOW not wired up. +*/ + +static void test_bug57058() +{ + MYSQL_RES *res; + int rc; + + DBUG_ENTER("test_bug57058"); + myheader("test_bug57058"); + + rc= mysql_query(mysql, "set @@session.long_query_time=0.1"); + myquery(rc); + + DIE_UNLESS(!(mysql->server_status & SERVER_QUERY_WAS_SLOW)); + + rc= mysql_query(mysql, "select sleep(1)"); + myquery(rc); + + /* + Important: the flag is sent in the last EOF packet of + the query, the one which ends the result. Read the + result to see the "slow" status. + */ + res= mysql_store_result(mysql); + + DIE_UNLESS(mysql->server_status & SERVER_QUERY_WAS_SLOW); + + mysql_free_result(res); + + rc= mysql_query(mysql, "set @@session.long_query_time=default"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + +/** + Bug#11766854: 60075: MYSQL_LOAD_CLIENT_PLUGIN DOESN'T CLEAR ERROR +*/ + +static void test_bug11766854() +{ + struct st_mysql_client_plugin *plugin; + + DBUG_ENTER("test_bug11766854"); + if (!getenv("QA_AUTH_CLIENT_SO")) + DBUG_VOID_RETURN; + + myheader("test_bug11766854"); + + plugin= mysql_load_plugin(mysql, "foo", -1, 0); + DIE_UNLESS(plugin == 0); + + plugin= mysql_load_plugin(mysql, "qa_auth_client", -1, 0); + DIE_UNLESS(plugin != 0); + DIE_IF(mysql_errno(mysql)); + + DBUG_VOID_RETURN; +} + +/** + Bug#12337762: 60075: MYSQL_LIST_FIELDS() RETURNS WRONG CHARSET FOR + CHAR/VARCHAR/TEXT COLUMNS IN VIEWS +*/ +static void test_bug12337762() +{ + int rc,i=0; + MYSQL_RES *result; + MYSQL_FIELD *field; + unsigned int tab_charsetnr[3]= {0}; + + DBUG_ENTER("test_bug12337762"); + myheader("test_bug12337762"); + + /* + Creating table with specific charset. + */ + rc= mysql_query(mysql, "drop table if exists charset_tab"); + rc= mysql_query(mysql, "create table charset_tab("\ + "txt1 varchar(32) character set Latin1,"\ + "txt2 varchar(32) character set Latin1 collate latin1_bin,"\ + "txt3 varchar(32) character set utf8 collate utf8_bin"\ + ")"); + + DIE_UNLESS(rc == 0); + DIE_IF(mysql_errno(mysql)); + + /* + Creating view from table created earlier. + */ + rc= mysql_query(mysql, "drop view if exists charset_view"); + rc= mysql_query(mysql, "create view charset_view as "\ + "select * from charset_tab;"); + DIE_UNLESS(rc == 0); + DIE_IF(mysql_errno(mysql)); + + /* + Checking field information for table. + */ + result= mysql_list_fields(mysql, "charset_tab", NULL); + DIE_IF(mysql_errno(mysql)); + i=0; + while((field= mysql_fetch_field(result))) + { + printf("field name %s\n", field->name); + printf("field table %s\n", field->table); + printf("field type %d\n", field->type); + printf("field charset %d\n", field->charsetnr); + tab_charsetnr[i++]= field->charsetnr; + printf("\n"); + } + mysql_free_result(result); + + /* + Checking field information for view. + */ + result= mysql_list_fields(mysql, "charset_view", NULL); + DIE_IF(mysql_errno(mysql)); + i=0; + while((field= mysql_fetch_field(result))) + { + printf("field name %s\n", field->name); + printf("field table %s\n", field->table); + printf("field type %d\n", field->type); + printf("field charset %d\n", field->charsetnr); + printf("\n"); + /* + charset value for field must be same for both, view and table. + */ + DIE_UNLESS(field->charsetnr == tab_charsetnr[i++]); + } + mysql_free_result(result); + + DBUG_VOID_RETURN; +} + +/* + MDEV-4603: mysql_stmt_reset doesn't clear + all result sets (from stored procedures). + This test requires also fix for MDEV-4604 +*/ +static void test_mdev4603() +{ + MYSQL *my; + MYSQL_STMT *stmt; + int i, rc; + int a[] = {10,20,30}; + MYSQL_BIND bind[3]; + + myheader("test_mdev4603"); + my= mysql_client_init(NULL); + + if (!mysql_real_connect(my, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_RESULTS)) + DIE("mysql_real_connect failed"); + + /* 1st test: + use a procedure with out param + */ + rc= mysql_query(my, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19), IN p_in INT, INOUT p_inout INT)" + "BEGIN " + " SET p_in = 300, p_out := 'This is OUT param', p_inout = 200; " + " SELECT p_inout, p_in, substring(p_out, 9);" + "END"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + DIE_UNLESS(stmt != NULL); + + rc= mysql_stmt_prepare(stmt, "CALL P1(?,?,?)", 14); + DIE_UNLESS(rc == 0); + + DIE_UNLESS(mysql_stmt_param_count(stmt) == 3); + + memset(bind, 0, sizeof(MYSQL_BIND) * 3); + for (i=0; i < 3; i++) + { + bind[i].buffer= &a[i]; + bind[i].buffer_type= MYSQL_TYPE_LONG; + } + bind[0].buffer_type= MYSQL_TYPE_NULL; + rc= mysql_stmt_bind_param(stmt, bind); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_reset(stmt); + DIE_UNLESS(rc == 0); + + /*connection shouldn't be blocked now */ + + rc= mysql_query(mysql, "DROP PROCEDURE p1"); + myquery(rc); + + /* 2nd test: + reset all result sets */ + rc= mysql_query(my, "CREATE PROCEDURE p1() " + "BEGIN" + " SELECT 1,2,3 FROM DUAL;" + " SELECT 'foo' FROM DUAL;" + "END"); + myquery(rc); + + rc= mysql_stmt_prepare(stmt, "CALL P1()", 9); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_reset(stmt); + DIE_UNLESS(rc == 0); + + /* 3rd test: + mysql_stmt_close should also flush all pending + result sets + */ + + rc= mysql_stmt_prepare(stmt, "CALL P1()", 9); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(my, "DROP PROCEDURE p1"); + myquery(rc); + + mysql_close(my); +} + +/* + BUG 11754979 - 46675: ON DUPLICATE KEY UPDATE AND UPDATECOUNT() POSSIBLY WRONG +*/ + +static void test_bug11754979() +{ + MYSQL* conn; + DBUG_ENTER("test_bug11754979"); + + myheader("test_bug11754979"); + DIE_UNLESS((conn= mysql_client_init(NULL))); + DIE_UNLESS(mysql_real_connect(conn, opt_host, opt_user, + opt_password, opt_db ? opt_db:"test", opt_port, + opt_unix_socket, CLIENT_FOUND_ROWS)); + myquery(mysql_query(conn, "DROP TABLE IF EXISTS t1")); + myquery(mysql_query(conn, "CREATE TABLE t1(id INT, label CHAR(1), PRIMARY KEY(id))")); + myquery(mysql_query(conn, "INSERT INTO t1(id, label) VALUES (1, 'a')")); + myquery(mysql_query(conn, "INSERT INTO t1(id, label) VALUES (1, 'a') " + "ON DUPLICATE KEY UPDATE id = 4")); + DIE_UNLESS(mysql_affected_rows(conn) == 2); + myquery(mysql_query(conn, "DROP TABLE t1")); + mysql_close(conn); + + DBUG_VOID_RETURN; +} + +static void test_ps_sp_out_params() +{ + MYSQL *my; + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char buffer[20]; + int status, rc; + + myheader("test_ps_sp_out_params"); + my= mysql_client_init(NULL); + + if (!mysql_real_connect(my, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_RESULTS)) + DIE("mysql_real_connect failed"); + + rc= mysql_query(my, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(my, + "CREATE PROCEDURE p1(OUT out_param VARCHAR(19)) " + "BEGIN" + " SELECT 'foo' FROM DUAL;" + " SET out_param='foo';" + " SELECT 'foo' FROM DUAL;" + "END"); + myquery(rc); + + stmt= mysql_stmt_init(my); + + rc= mysql_stmt_prepare(stmt, "CALL P1(?)", 10); + DIE_UNLESS(rc==0); + + DIE_UNLESS(mysql_stmt_param_count(stmt) == 1); + + memset(bind, 0, sizeof(MYSQL_BIND)); + memset(buffer, 0, sizeof buffer); + bind[0].buffer= buffer; + bind[0].buffer_length= sizeof(buffer); + bind[0].buffer_type= MYSQL_TYPE_STRING; + + mysql_stmt_bind_param(stmt, bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + do { + if (mysql_stmt_field_count(stmt)) + { + /* since server sends a status packet at the end, + there must follow at least one additional packet */ + DIE_UNLESS(mysql_more_results(stmt->mysql)); + + mysql_stmt_bind_result(stmt, bind); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc== 0); + + DIE_UNLESS(strcmp(buffer, "foo") == 0); + } + status= mysql_stmt_next_result(stmt); + } while (status == 0); + + rc= mysql_stmt_reset(stmt); + DIE_UNLESS(rc== 0); + + mysql_stmt_close(stmt); + mysql_close(my); + + printf("end\n"); +} + +/* + Bug#13001491: MYSQL_REFRESH CRASHES WHEN STORED ROUTINES ARE RUN CONCURRENTLY. +*/ +static void test_bug13001491() +{ + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + MYSQL *c; + + myheader("test_bug13001491"); + + my_snprintf(query, MAX_TEST_QUERY_LENGTH, + "GRANT ALL PRIVILEGES ON *.* TO mysqltest_u1@%s", + opt_host ? opt_host : "'localhost'"); + + rc= mysql_query(mysql, query); + myquery(rc); + + my_snprintf(query, MAX_TEST_QUERY_LENGTH, + "GRANT RELOAD ON *.* TO mysqltest_u1@%s", + opt_host ? opt_host : "'localhost'"); + + rc= mysql_query(mysql, query); + myquery(rc); + + c= mysql_client_init(NULL); + + DIE_UNLESS(mysql_real_connect(c, opt_host, "mysqltest_u1", NULL, + current_db, opt_port, opt_unix_socket, + CLIENT_MULTI_STATEMENTS | + CLIENT_MULTI_RESULTS)); + + rc= mysql_query(c, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(c, + "CREATE PROCEDURE p1() " + "BEGIN " + " DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END; " + " SELECT COUNT(*) " + " FROM INFORMATION_SCHEMA.PROCESSLIST " + " GROUP BY user " + " ORDER BY NULL " + " INTO @a; " + "END"); + myquery(rc); + + rc= mysql_query(c, "CALL p1()"); + myquery(rc); + + mysql_free_result(mysql_store_result(c)); + + /* Check that mysql_refresh() succeeds without REFRESH_LOG. */ + rc= mysql_refresh(c, REFRESH_GRANT | + REFRESH_TABLES | REFRESH_HOSTS | + REFRESH_STATUS | REFRESH_THREADS); + myquery(rc); + + /* + Check that mysql_refresh(REFRESH_LOG) does not crash the server even if it + fails. mysql_refresh(REFRESH_LOG) fails when error log points to unavailable + location. + */ + mysql_refresh(c, REFRESH_LOG); + + rc= mysql_query(c, "DROP PROCEDURE p1"); + myquery(rc); + + mysql_close(c); + c= NULL; + + my_snprintf(query, MAX_TEST_QUERY_LENGTH, + "DROP USER mysqltest_u1@%s", + opt_host ? opt_host : "'localhost'"); + + rc= mysql_query(mysql, query); + myquery(rc); +} + +static void test_mdev4326() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind; + char query[]= "SELECT * FROM mysql.user LIMIT ?"; + char str_data[]= "1"; + unsigned long length= 0; + int int_data= 1; + int rc, count; + my_bool is_null= 0; + my_bool error= 0; + myheader("test_mdev4326"); + + rc= mysql_change_user(mysql, opt_user, opt_password, "mysql"); + myquery(rc); + + rc= mysql_query(mysql, "SET GLOBAL general_log = 1"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + /* Numeric parameter test */ + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + check_stmt(stmt); + verify_param_count(stmt, 1); + + memset((char *)&bind, 0, sizeof(bind)); + bind.buffer_type= MYSQL_TYPE_LONG; + bind.buffer= (char *)&int_data; + bind.is_null= &is_null; + bind.length= &length; + bind.error= &error; + + rc= mysql_stmt_bind_param(stmt, &bind); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 1); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 1); + int_data= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 0); + rc= mysql_stmt_close(stmt); + check_execute(stmt, rc); + + /* String parameter test */ + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + check_stmt(stmt); + verify_param_count(stmt, 1); + + memset((char *)&bind, 0, sizeof(bind)); + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer= (char *)str_data; + length= bind.buffer_length= sizeof(str_data); + bind.is_null= &is_null; + bind.length= &length; + bind.error= &error; + + rc= mysql_stmt_bind_param(stmt, &bind); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 1); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 1); + str_data[0]= '0'; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 0); + rc= mysql_stmt_close(stmt); + check_execute(stmt, rc); + + rc= mysql_change_user(mysql, opt_user, opt_password, current_db); + myquery(rc); +} + +/* Test uses MYSQL_PROTOCOL_SOCKET, not on Windows */ + +#ifndef _WIN32 +/** + BUG#17512527: LIST HANDLING INCORRECT IN MYSQL_PRUNE_STMT_LIST() +*/ +static void test_bug17512527() +{ + MYSQL *conn; + MYSQL_STMT *stmt1, *stmt2; + unsigned long thread_id; + char query[MAX_TEST_QUERY_LENGTH]; + int rc; + + conn= client_connect(0, MYSQL_PROTOCOL_SOCKET, 1); + + stmt1 = mysql_stmt_init(conn); + check_stmt(stmt1); + rc= mysql_stmt_prepare(stmt1, STRING_WITH_LEN("SELECT 1")); + check_execute(stmt1, rc); + + stmt2 = mysql_stmt_init(conn); + check_stmt(stmt2); + + thread_id= mysql_thread_id(conn); + sprintf(query, "KILL %lu", thread_id); + if (thread_query(query)) + exit(1); + + rc= mysql_stmt_prepare(stmt2, STRING_WITH_LEN("SELECT 2")); + check_execute(stmt2, rc); + + rc= mysql_stmt_execute(stmt1); + check_execute_r(stmt1, rc); + + rc= mysql_stmt_execute(stmt2); + check_execute(stmt2, rc); + + mysql_close(conn); + + mysql_stmt_close(stmt2); + mysql_stmt_close(stmt1); +} +#endif + + +/* + Check compressed protocol +*/ + +static void test_compressed_protocol() +{ + MYSQL *mysql_local; + MYSQL_STMT *stmt; + char query[4096], *end; + int i; + int rc; + myheader("test_compressed_protocol"); + + if (!(mysql_local= mysql_client_init(NULL))) + { + fprintf(stderr, "\n mysql_client_init() failed"); + exit(1); + } + + if (!(mysql_real_connect(mysql_local, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_COMPRESS))) + { + fprintf(stderr, "\n connection failed(%s)", mysql_error(mysql_local)); + exit(1); + } + mysql_options(mysql_local,MYSQL_OPT_COMPRESS,NullS); + + end= strmov(strfill(strmov(query, "select length(\""),1000,'a'),"\")"); + + for (i=0 ; i < 2 ; i++) + { + MYSQL_RES *res; + rc= mysql_real_query(mysql, query, (int) (end-query)); + myquery(rc); + res= mysql_store_result(mysql); + DBUG_ASSERT(res != 0); + mysql_free_result(res); + } + + /* + Special compression protocol feature - it can pack + multiple protocol commands inside the same compression packet. + + mariadbclient does it when MYSQL_STMT is reused in multiple + mysql_stmt_prepare() calls. It sends then COM_STMT_CLOSE and + COM_STMT_PREPARE together in a single compression packet. + + Let's test, how server can handle that. There can be bugs + (MDEV-28561) + */ + stmt= mysql_stmt_init(mysql_local); + check_stmt(stmt); + for (i= 0; i < 2; i++) + { + rc= mysql_stmt_prepare(stmt, "DO 1", -1); + myquery(rc); + } + rc= mysql_stmt_close(stmt); + myquery(rc); + + mysql_close(mysql_local); +} + +/* + Check big packets +*/ + +static void test_big_packet() +{ + MYSQL *mysql_local; + char *query, *end; + /* We run the tests with a server with max packet size of 3200000 */ + size_t big_packet= 31000000L; + int i; + MYSQL_PARAMETERS *mysql_params= mysql_get_parameters(); + long org_max_allowed_packet= *mysql_params->p_max_allowed_packet; + long opt_net_buffer_length= *mysql_params->p_net_buffer_length; + + myheader("test_big_packet"); + + query= (char*) my_malloc(PSI_NOT_INSTRUMENTED, big_packet+1024, MYF(MY_WME)); + DIE_UNLESS(query); + + if (!(mysql_local= mysql_client_init(NULL))) + { + fprintf(stderr, "\n mysql_client_init() failed"); + exit(1); + } + + if (!(mysql_real_connect(mysql_local, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + fprintf(stderr, "\n connection failed(%s)", mysql_error(mysql_local)); + mysql_close(mysql_local); + exit(1); + } + + *mysql_params->p_max_allowed_packet= big_packet+1000; + *mysql_params->p_net_buffer_length= 8L*256L*256L; + + end= strmov(strfill(strmov(query, "select length(\""), big_packet,'a'),"\")"); + + for (i=0 ; i < 2 ; i++) + { + MYSQL_RES *res; + int rc= mysql_real_query(mysql, query, (int) (end-query)); + myquery(rc); + res= mysql_store_result(mysql); + DBUG_ASSERT(res != 0); + mysql_free_result(res); + } + + mysql_close(mysql_local); + my_free(query); + + *mysql_params->p_max_allowed_packet= org_max_allowed_packet; + *mysql_params->p_net_buffer_length = opt_net_buffer_length; +} + + +static void test_prepare_analyze() +{ + MYSQL_STMT *stmt; + const char *query= "ANALYZE SELECT 1"; + int rc; + myheader("test_prepare_analyze"); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + while (!(rc= mysql_stmt_fetch(stmt))) + ; + + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_close(stmt); + check_execute(stmt, rc); +} + +static void test_mdev12579() +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + MYSQL_BIND bind[2]; + int rc; + long l=3; + const char *data = "123456"; + + rc= mysql_query(mysql, "CREATE TABLE mdev12579 (k integer,t LONGTEXT,b LONGBLOB,x integer)"); + myquery(rc); + + rc= mysql_stmt_prepare(stmt, "INSERT INTO mdev12579 VALUES (1,?,NULL,?)", -1); + myquery(rc); + + rc= mysql_stmt_send_long_data(stmt, 0, data, 6); + rc= mysql_stmt_send_long_data(stmt, 0, data, 6); + rc= mysql_stmt_send_long_data(stmt, 0, data, 6); + + memset(bind, 0, sizeof(MYSQL_BIND) * 2); + bind[0].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= &l; + mysql_stmt_bind_param(stmt, bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE mdev12579"); + myquery(rc); +} + +/* Test test_mdev14013 sql_mode=EMPTY_STRING_IS_NULL */ + +static void test_mdev14013() +{ + MYSQL *lmysql; + MYSQL_STMT *stmt1; + MYSQL_BIND my_bind[2]; + MYSQL_RES *result; + char str_data[20]; + unsigned int count; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_mdev14013"); + + if (!opt_silent) + fprintf(stdout, "\n Establishing a test connection ..."); + if (!(lmysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + exit(1); + } + if (!(mysql_real_connect(lmysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + exit(1); + } + mysql_options(lmysql, MYSQL_OPT_RECONNECT, &my_true); + if (!opt_silent) + fprintf(stdout, "OK"); + + /* set AUTOCOMMIT to ON*/ + mysql_autocommit(lmysql, TRUE); + + strmov(query, "SET SQL_MODE= \"EMPTY_STRING_IS_NULL\""); + if (!opt_silent) + fprintf(stdout, "\n With %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + rc= mysql_query(lmysql, "DROP TABLE IF EXISTS test_mdev14013"); + myquery(rc); + + rc= mysql_query(lmysql, "CREATE TABLE test_mdev14013(id int, val varchar(10))"); + myquery(rc); + + strmov(query, "INSERT INTO test_mdev14013(id,val) VALUES(?,?)"); + stmt1= mysql_simple_prepare(mysql, query); + check_stmt(stmt1); + + verify_param_count(stmt1, 2); + + /* + We need to bzero bind structure because mysql_stmt_bind_param checks all + its members. + */ + bzero((char*) my_bind, sizeof(my_bind)); + + my_bind[0].buffer= (void *)&count; + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + count= 100; + + strcpy(str_data,""); + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (char *) str_data; + my_bind[1].buffer_length= strlen(str_data); + + rc= mysql_stmt_bind_param(stmt1, my_bind); + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + verify_st_affected_rows(stmt1, 1); + + rc= mysql_stmt_close(stmt1); + + strmov(query, "SET SQL_MODE= default"); + if (!opt_silent) + fprintf(stdout, "\n With %s\n", query); + rc= mysql_query(mysql, query); + myquery(rc); + + strmov(query, "INSERT INTO test_mdev14013(id,val) VALUES(?,?)"); + stmt1= mysql_simple_prepare(mysql, query); + check_stmt(stmt1); + + count= 200; + rc= mysql_stmt_bind_param(stmt1, my_bind); + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + verify_st_affected_rows(stmt1, 1); + + rc= mysql_stmt_close(stmt1); + if (!opt_silent) + fprintf(stdout, "\n test_mdev14013(x) returned: %d", rc); + DIE_UNLESS( rc == 0); + + rc= mysql_query(mysql, "SELECT id, val FROM test_mdev14013 order by id"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 2); + mysql_free_result(result); + + rc= mysql_query(mysql, "SELECT id, val FROM test_mdev14013 where val is null"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + mysql_free_result(result); + + myquery(mysql_query(mysql, "drop table test_mdev14013")); + mysql_close(lmysql); +} + +static void test_mdev14013_1() +{ + MYSQL *lmysql; + MYSQL_STMT *stmt1; + MYSQL_BIND my_bind[3]; + char str_data[3][255]; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_mdev14013_1"); + + if (!opt_silent) + fprintf(stdout, "\n Establishing a test connection ..."); + if (!(lmysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + exit(1); + } + if (!(mysql_real_connect(lmysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + exit(1); + } + mysql_options(lmysql, MYSQL_OPT_RECONNECT, &my_true); + if (!opt_silent) + fprintf(stdout, "OK"); + + /* set AUTOCOMMIT to ON*/ + mysql_autocommit(lmysql, TRUE); + + strmov(query, "SET SQL_MODE= \"EMPTY_STRING_IS_NULL\""); + if (!opt_silent) + fprintf(stdout, "\n With %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + rc= mysql_query(mysql, + "CREATE OR REPLACE PROCEDURE test_mdev14013_p1(" + " IN i1 VARCHAR(255) , " + " INOUT io1 VARCHAR(255), " + " OUT o2 VARBINARY(255)) " + "BEGIN " + " SET o2 = concat(concat(coalesce(i1,'i1 is null'),' - '),coalesce(i1,'io1 is null')); " + "END"); + myquery(rc); + + strmov(query, "CALL test_mdev14013_p1(?, ?, ?)"); + stmt1= mysql_simple_prepare(mysql, query); + check_stmt(stmt1); + + /* Init PS-parameters. */ + + bzero((char *) my_bind, sizeof (my_bind)); + + strcpy(str_data[0],""); + my_bind[0].buffer_type= MYSQL_TYPE_STRING; + my_bind[0].buffer= (char *) str_data[0]; + my_bind[0].buffer_length= strlen(str_data[0]); + + strcpy(str_data[1],""); + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (char *) str_data[1]; + my_bind[1].buffer_length= strlen(str_data[1]); + + strcpy(str_data[2],""); + my_bind[2].buffer_type= MYSQL_TYPE_STRING; + my_bind[2].buffer= (char *) str_data[2]; + my_bind[2].buffer_length= strlen(str_data[2]); + + /* Bind parameters. */ + + rc= mysql_stmt_bind_param(stmt1, my_bind); + check_execute(stmt1, rc); + /* Execute */ + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + my_bind[0].buffer_length= sizeof(str_data[0]); + my_bind[1].buffer_length= sizeof(str_data[1]); + + mysql_stmt_bind_result(stmt1, my_bind); + rc= mysql_stmt_fetch(stmt1); + + if (!opt_silent) + fprintf(stdout,"\nstr_data[1]=%s\n",str_data[1]); + + DIE_UNLESS(strcmp(str_data[1], "i1 is null - io1 is null") == 0); + + rc= mysql_stmt_close(stmt1); + DIE_UNLESS( rc == 0); + + myquery(mysql_query(mysql, "drop procedure test_mdev14013_p1")); + mysql_close(lmysql); +} + + +static void test_mdev14454_internal(const char *init, + unsigned int csid, + const char *value) +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind; + const char *stmtstr= "CALL P1(?)"; + char res[20]; + int rc; + + if ((rc= mysql_query_or_error(mysql, init)) || + (rc= mysql_query_or_error(mysql, "DROP PROCEDURE IF EXISTS p1")) || + (rc= mysql_query_or_error(mysql, + "CREATE PROCEDURE p1" + "(" + " OUT param1 TEXT CHARACTER SET utf8" + ")" + "BEGIN " + " SET param1 = _latin1'test\xFF'; " + "END"))) + DIE("Initiation failed"); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr)); + DIE_UNLESS(rc == 0); + DIE_UNLESS(mysql_stmt_param_count(stmt) == 1); + + memset(&bind, 0, sizeof bind); + bind.buffer_type= MYSQL_TYPE_NULL; + rc= mysql_stmt_bind_param(stmt, &bind); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + memset(res, 0, sizeof(res)); + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer_length= sizeof(res); + bind.buffer= res; + + do { + if (mysql->server_status & SERVER_PS_OUT_PARAMS) + { + MYSQL_FIELD *field; + printf("\nOUT param result set:\n"); + DIE_UNLESS(mysql_stmt_field_count(stmt) == 1); + field= &stmt->fields[0]; + printf("Field: %s\n", field->name); + printf("Type: %d\n", field->type); + printf("Collation: %d\n", field->charsetnr); + printf("Length: %lu\n", field->length); + DIE_UNLESS(stmt->fields[0].charsetnr == csid); + + rc= mysql_stmt_bind_result(stmt, &bind); + DIE_UNLESS(rc == 0); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + printf("Value: %s\n", res); + DIE_UNLESS(strcmp(res, value) == 0); + } + else if (mysql_stmt_field_count(stmt)) + { + printf("sp result set\n"); + } + } while (mysql_stmt_next_result(stmt) == 0); + + mysql_stmt_close(stmt); + DIE_UNLESS(mysql_query_or_error(mysql, "DROP PROCEDURE p1") == 0); +} + + +static void test_mdev14454() +{ + myheader("test_mdev14454"); + test_mdev14454_internal("SET NAMES latin1", 8, "test\xFF"); + test_mdev14454_internal("SET NAMES utf8", 33, "test\xC3\xBF"); +} + + +typedef struct { + char sig[12]; + char ver_cmd; + char fam; + short len; + union { + struct { /* for TCP/UDP over IPv4, len = 12 */ + int src_addr; + int dst_addr; + short src_port; + short dst_port; + } ip4; + struct { /* for TCP/UDP over IPv6, len = 36 */ + char src_addr[16]; + char dst_addr[16]; + short src_port; + short dst_port; + } ip6; + struct { /* for AF_UNIX sockets, len = 216 */ + char src_addr[108]; + char dst_addr[108]; + } unx; + } addr; +} v2_proxy_header; + +#ifndef EMBEDDED_LIBRARY +static void test_proxy_header_tcp(const char *ipaddr, int port) +{ + + int rc; + MYSQL_RES *result; + int family = (strchr(ipaddr,':') == NULL)?AF_INET:AF_INET6; + char query[256]; + char text_header[256]; + char addr_bin[16]; + v2_proxy_header v2_header; + void *header_data[2]; + size_t header_lengths[2]; + int i; + + // normalize IPv4-mapped IPv6 addresses, e.g ::ffff:127.0.0.2 to 127.0.0.2 + const char *normalized_addr= strncmp(ipaddr, "::ffff:", 7)?ipaddr : ipaddr + 7; + myheader("test_proxy_header_tcp"); + + memset(&v2_header, 0, sizeof(v2_header)); + sprintf(text_header,"PROXY %s %s %s %d 3306\r\n",family == AF_INET?"TCP4":"TCP6", ipaddr, ipaddr, port); + + inet_pton(family,ipaddr,addr_bin); + + memcpy(v2_header.sig, "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12); + v2_header.ver_cmd = (0x2 << 4) | 0x1; /* Version (0x2) , Command = PROXY (0x1) */ + if(family == AF_INET) + { + v2_header.fam= 0x11; + v2_header.len= htons(12); + v2_header.addr.ip4.src_port= htons(port); + v2_header.addr.ip4.dst_port= htons(3306); + memcpy(&v2_header.addr.ip4.src_addr,addr_bin, sizeof (v2_header.addr.ip4.src_addr)); + memcpy(&v2_header.addr.ip4.dst_addr,addr_bin, sizeof (v2_header.addr.ip4.dst_addr)); + } + else + { + v2_header.fam= 0x21; + v2_header.len= htons(36); + v2_header.addr.ip6.src_port= htons(port); + v2_header.addr.ip6.dst_port= htons(3306); + memcpy(v2_header.addr.ip6.src_addr,addr_bin, sizeof (v2_header.addr.ip6.src_addr)); + memcpy(v2_header.addr.ip6.dst_addr,addr_bin, sizeof (v2_header.addr.ip6.dst_addr)); + } + + sprintf(query,"CREATE USER 'u'@'%s' IDENTIFIED BY 'password'",normalized_addr); + rc= mysql_query(mysql, query); + myquery(rc); + + header_data[0]= text_header; + header_data[1]= &v2_header; + + header_lengths[0]= strlen(text_header); + header_lengths[1]= family == AF_INET ? 28 : 52; + + for (i = 0; i < 2; i++) + { + MYSQL *m; + size_t addrlen; + MYSQL_ROW row; + m = mysql_client_init(NULL); + DIE_UNLESS(m); + mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, header_data[i], header_lengths[i]); + if (!mysql_real_connect(m, opt_host, "u", "password", NULL, opt_port, opt_unix_socket, 0)) + { + DIE_UNLESS(0); + } + rc= mysql_query(m, "select host from information_schema.processlist WHERE ID = connection_id()"); + myquery(rc); + /* get the result */ + result= mysql_store_result(m); + mytest(result); + row = mysql_fetch_row(result); + addrlen = strlen(normalized_addr); + printf("%.*s %.*s\n", (int)addrlen, row[0], (int)addrlen, normalized_addr); + DIE_UNLESS(strncmp(row[0], normalized_addr, addrlen) == 0); + DIE_UNLESS(atoi(row[0] + addrlen+1) == port); + mysql_free_result(result); + mysql_close(m); + } + sprintf(query,"DROP USER 'u'@'%s'",normalized_addr); + rc = mysql_query(mysql, query); + myquery(rc); +} + + +/* Test proxy protocol with AF_UNIX (localhost) */ +static void test_proxy_header_localhost() +{ + v2_proxy_header v2_header; + void *header_data = &v2_header; + size_t header_length= 216 + 16; + MYSQL *m; + MYSQL_RES *result; + MYSQL_ROW row; + int rc; + myheader("test_proxy_header_localhost"); + + memset(&v2_header, 0, sizeof(v2_header)); + memcpy(v2_header.sig, "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12); + v2_header.ver_cmd = (0x2 << 4) | 0x1; /* Version (0x2) , Command = PROXY (0x1) */ + v2_header.fam= 0x31; + v2_header.len= htons(216); + strcpy(v2_header.addr.unx.src_addr,"/tmp/mysql.sock"); + strcpy(v2_header.addr.unx.dst_addr,"/tmp/mysql.sock"); + rc = mysql_query(mysql, "CREATE USER 'u'@'localhost' IDENTIFIED BY 'password'"); + myquery(rc); + m = mysql_client_init(NULL); + DIE_UNLESS(m != NULL); + mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, header_data, header_length); + DIE_UNLESS(mysql_real_connect(m, opt_host, "u", "password", NULL, opt_port, opt_unix_socket, 0) == m); + DIE_UNLESS(mysql_query(m, "select host from information_schema.processlist WHERE ID = connection_id()") == 0); + /* get the result */ + result= mysql_store_result(m); + mytest(result); + row = mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "localhost") == 0); + mysql_free_result(result); + mysql_close(m); + rc = mysql_query(mysql, "DROP USER 'u'@'localhost'"); + myquery(rc); +} + +/* Proxy header ignoring */ +static void test_proxy_header_ignore() +{ + int rc; + MYSQL *m = mysql_client_init(NULL); + v2_proxy_header v2_header; + myheader("test_ps_params_in_ctes"); + DIE_UNLESS(m != NULL); + mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, "PROXY UNKNOWN\r\n",15); + DIE_UNLESS(mysql_real_connect(m, opt_host, "root", "", NULL, opt_port, opt_unix_socket, 0) == m); + mysql_close(m); + + memcpy(v2_header.sig, "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12); + v2_header.ver_cmd = (0x2 << 4) | 0x0; /* Version (0x2) , Command = LOCAL (0x0) */ + v2_header.fam= 0x0; /* AF_UNSPEC*/ + v2_header.len= htons(0); + m = mysql_client_init(NULL); + mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, &v2_header,16); + DIE_UNLESS(mysql_real_connect(m, opt_host, "root", "", NULL, opt_port, opt_unix_socket, 0) == m); + mysql_close(m); + + /* test for connection denied with empty proxy_protocol_networks */ + rc = mysql_query(mysql, "select @@proxy_protocol_networks into @sv_proxy_protocol_networks"); + myquery(rc); + mysql_query(mysql, "set global proxy_protocol_networks=default"); + myquery(rc); + m = mysql_client_init(NULL); + mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, &v2_header,16); + DIE_UNLESS(mysql_real_connect(m, opt_host, "root", "", NULL, opt_port, opt_unix_socket, 0) == 0); + mysql_close(m); + mysql_query(mysql, "set global proxy_protocol_networks= @sv_proxy_protocol_networks"); + myquery(rc); +} + + +static void test_proxy_header() +{ + myheader("test_proxy_header"); + test_proxy_header_tcp("192.0.2.1",3333); + test_proxy_header_tcp("2001:db8:85a3::8a2e:370:7334",2222); + test_proxy_header_tcp("::ffff:192.0.2.1",2222); + test_proxy_header_localhost(); + test_proxy_header_ignore(); +} + + +static void test_bulk_autoinc() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + MYSQL_ROW row; + char indicator[]= {0, STMT_INDICATOR_NULL, 0/*STMT_INDICATOR_IGNORE*/}; + my_bool error[1]; + int i, id[]= {2, 3, 777}, count= sizeof(id)/sizeof(id[0]); + MYSQL_RES *result; + + myheader("test_bulk_autoinc"); + rc= mysql_query(mysql, "DROP TABLE IF EXISTS ai_field_value"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE ai_field_value (id int not null primary key auto_increment)"); + myquery(rc); + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, "INSERT INTO ai_field_value(id) values(?)", -1); + check_execute(stmt, rc); + + memset(bind, 0, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_LONG; + bind[0].buffer = (void *)id; + bind[0].buffer_length = 0; + bind[0].is_null = NULL; + bind[0].length = NULL; + bind[0].error = error; + bind[0].u.indicator= indicator; + + mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, (void*)&count); + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "SELECT id FROM ai_field_value"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + i= 0; + while ((row= mysql_fetch_row(result))) + { + DIE_IF(atoi(row[0]) != id[i++]); + } + mysql_free_result(result); + rc= mysql_query(mysql, "DROP TABLE ai_field_value"); + myquery(rc); +} + +static void test_bulk_delete() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + MYSQL_ROW row; + char indicator[]= {0, 0, 0}; + my_bool error[1]; + int i, id[]= {1, 2, 4}, count= sizeof(id)/sizeof(id[0]); + MYSQL_RES *result; + + myheader("test_bulk_delete"); + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1 (id int not null primary key)"); + myquery(rc); + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1),(2),(3),(4)"); + myquery(rc); + verify_affected_rows(4); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, "DELETE FROM t1 where id=?", -1); + check_execute(stmt, rc); + + memset(bind, 0, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_LONG; + bind[0].buffer = (void *)id; + bind[0].buffer_length = 0; + bind[0].is_null = NULL; + bind[0].length = NULL; + bind[0].error = error; + bind[0].u.indicator= indicator; + + mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, (void*)&count); + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + verify_affected_rows(3); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "SELECT id FROM t1"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + i= 0; + while ((row= mysql_fetch_row(result))) + { + i++; + DIE_IF(atoi(row[0]) != 3); + } + DIE_IF(i != 1); + mysql_free_result(result); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + +static void test_bulk_replace() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_BIND bind[2]; + MYSQL_ROW row; + int i, + id[]= {1, 2, 3, 4}, + val[]= {1, 1, 1, 1}, + count= sizeof(id)/sizeof(id[0]); + MYSQL_RES *result; + + myheader("test_bulk_replace"); + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1 (id int not null primary key, active int)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1, 0), (2, 0), (3, 0)"); + myquery(rc); + verify_affected_rows(3); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, "replace into t1 (id, active) values (?, ?)", -1); + check_execute(stmt, rc); + + memset(bind, 0, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_LONG; + bind[0].buffer = (void *)id; + bind[0].buffer_length = 0; + bind[1].buffer_type = MYSQL_TYPE_LONG; + bind[1].buffer = (void *)val; + bind[1].buffer_length = 0; + + mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, (void*)&count); + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "SELECT active FROM t1"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + i= 0; + while ((row= mysql_fetch_row(result))) + { + i++; + DIE_IF(atoi(row[0]) != 1); + } + DIE_IF(i != 4); + mysql_free_result(result); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + + +static void test_bulk_insert_returning() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_BIND bind[2], res_bind[2]; + MYSQL_ROW row; + MYSQL_RES *result; + int i, + id[]= {1, 2, 3, 4}, + val[]= {1, 1, 1, 1}, + count= sizeof(id)/sizeof(id[0]); + unsigned long length[2]; + my_bool is_null[2]; + my_bool error[2]; + int32 res[2]; + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, + "CREATE TABLE t1 (id int not null primary key, active int)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, + "insert into t1 values (?, ?) returning id, active", + -1); + check_execute(stmt, rc); + + memset(bind, 0, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_LONG; + bind[0].buffer = (void *)id; + bind[0].buffer_length = 0; + bind[1].buffer_type = MYSQL_TYPE_LONG; + bind[1].buffer = (void *)val; + bind[1].buffer_length = 0; + + mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, (void*)&count); + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + myquery(rc); + + memset(res_bind, 0, sizeof(res_bind)); + for (i= 0; i < 2; i++) + { + res_bind[i].buffer_type= MYSQL_TYPE_LONG; + res_bind[i].buffer= (char *)&res[i]; + res_bind[i].is_null= &is_null[i]; + res_bind[i].length= &length[i]; + res_bind[i].error= &error[i]; + } + rc= mysql_stmt_bind_result(stmt, res_bind); + myquery(rc); + rc= mysql_stmt_store_result(stmt); + myquery(rc); + + i= 0; + while (!mysql_stmt_fetch(stmt)) + { + i++; + DIE_IF(is_null[0] || is_null[1]); + DIE_IF(res[0] != i); + DIE_IF(res[1] != 1); + } + DIE_IF(i != 4); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "SELECT id,active FROM t1"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + i= 0; + while ((row= mysql_fetch_row(result))) + { + i++; + DIE_IF(atoi(row[0]) != i); + DIE_IF(atoi(row[1]) != 1); + } + DIE_IF(i != 4); + mysql_free_result(result); + + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + +static void test_bulk_delete_returning() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_BIND bind[2], res_bind[2]; + MYSQL_ROW row; + MYSQL_RES *result; + int i, + id[]= {1, 2, 3, 4}, + count= sizeof(id)/sizeof(id[0]); + unsigned long length[1]; + my_bool is_null[1]; + my_bool error[1]; + int32 res[1]; + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1 (id int not null primary key)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1), (2), (3), (4)"); + myquery(rc); + verify_affected_rows(4); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, "DELETE FROM t1 WHERE id=? RETURNING id", -1); + check_execute(stmt, rc); + + memset(bind, 0, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_LONG; + bind[0].buffer = (void *)id; + bind[0].buffer_length = 0; + + mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, (void*)&count); + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + myquery(rc); + + memset(res_bind, 0, sizeof(res_bind)); + res_bind[0].buffer_type= MYSQL_TYPE_LONG; + res_bind[0].buffer= (char *)&res[0]; + res_bind[0].is_null= &is_null[0]; + res_bind[0].length= &length[0]; + res_bind[0].error= &error[0]; + rc= mysql_stmt_bind_result(stmt, res_bind); + myquery(rc); + rc= mysql_stmt_store_result(stmt); + myquery(rc); + + i= 0; + while (!mysql_stmt_fetch(stmt)) + { + i++; + DIE_IF(is_null[0]); + DIE_IF(res[0] != i); + } + DIE_IF(i != 4); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "SELECT id FROM t1"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + i= 0; + while ((row= mysql_fetch_row(result))) + { + i++; + printf("\nResult (SHOULD NOT BE HERE!!!) %d %s \n", i, row[0]); + } + DIE_IF(i != 0 ); + mysql_free_result(result); + + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} +#endif + + +static void test_ps_params_in_ctes() +{ + int rc; + const char *query; + MYSQL_BIND ps_params[1]; + int int_data[1]; + MYSQL_STMT *stmt; + + myheader("test_ps_params_in_ctes"); + rc= mysql_query(mysql, "create table t1(a int, b int, key(a))"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t1 (a) values " + "(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)"); + myquery(rc); + + query= + "explain " + "with T as " + "( " + " select * from t1 where t1.a=? limit 2 " + ") " + "select * from T as TA, T as TB;"; + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + rc= mysql_stmt_prepare(stmt, query, (uint) strlen(query)); + check_execute(stmt, rc); + + int_data[0]=2; + + memset(ps_params, 0, sizeof ps_params); + ps_params[0].buffer_type= MYSQL_TYPE_LONG; + ps_params[0].buffer= (char *) &int_data[0]; + ps_params[0].length= 0; + ps_params[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, ps_params); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + +void display_result_metadata(MYSQL_FIELD *field, + uint num_fields) +{ + MYSQL_FIELD* field_end; + + mct_log("Catalog\tDatabase\tTable\tTable_alias\tColumn\t" + "Column_alias\tType\tLength\tMax length\tIs_null\t" + "Flags\tDecimals\tCharsetnr\n"); + for (field_end= field+num_fields; field < field_end; field++) + { + mct_log("%s\t", field->catalog); + mct_log("%s\t", field->db); + mct_log("%s\t", field->org_table); + mct_log("%s\t", field->table); + mct_log("%s\t", field->org_name); + mct_log("%s\t", field->name); + mct_log("%u\t", field->type); + mct_log("%lu\t", field->length); + mct_log("%lu\t", field->max_length); + mct_log("%s\t", (IS_NOT_NULL(field->flags) ? "N" : "Y")); + mct_log("%u\t", field->flags); + mct_log("%u\t", field->decimals); + mct_log("%u\n", field->charsetnr); + } +} + +static void test_mdev_26145() +{ + MYSQL_STMT *stmt; + MYSQL_RES *result; + MYSQL_FIELD *fields; + int rc, num_fields; + + myheader("test_mdev_26145"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1(a INT)"); + myquery(rc); + + stmt= mysql_simple_prepare( + mysql, "(SELECT MAX(a) FROM t1) UNION (SELECT MAX(a) FROM t1)"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + result= mysql_stmt_result_metadata(stmt); + DIE_UNLESS(result); + + num_fields= mysql_stmt_field_count(stmt); + fields= mysql_fetch_fields(result); + + mct_start_logging("test_mdev26145"); + display_result_metadata(fields, num_fields); + mct_close_log(); + + mysql_free_result(result); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + + myquery(rc); +} + +static void test_mdev24827() +{ + int rc; + MYSQL_STMT *stmt; + unsigned long cursor = CURSOR_TYPE_READ_ONLY; + const char* query= + "SELECT t2.c1 AS c1 FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1 " + "WHERE EXISTS (SELECT 1 FROM t1 WHERE c2 = -1) ORDER BY c1"; + + myheader("test_mdev24827"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t2"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2 (c1 INT PRIMARY KEY, c2 INT, " + "KEY idx_c2(c2))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 (c1, c2) " + "SELECT seq, seq FROM seq_1_to_10000"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t2 (c1, c2) " + "SELECT seq, seq FROM seq_1_to_20000"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &cursor); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE t2"); + myquery(rc); +} + +static void test_mdev_20516() +{ + MYSQL_STMT *stmt; + int rc; + unsigned long cursor= CURSOR_TYPE_READ_ONLY; + const char* query= + "CREATE VIEW v1 AS SELECT * FROM t1"; + + myheader("test_mdev_20516"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1(a INT)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &cursor); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + +static void print_metadata(MYSQL_RES *rs_metadata, int num_fields) +{ + int i; + MYSQL_FIELD *fields= mysql_fetch_fields(rs_metadata); + + for (i = 0; i < num_fields; ++i) + { + mct_log(" - %d: name: '%s'/'%s'; table: '%s'/'%s'; " + "db: '%s'; catalog: '%s'; length: %d; max_length: %d; " + "type: %d; decimals: %d\n", + (int) i, + (const char *) fields[i].name, + (const char *) fields[i].org_name, + (const char *) fields[i].table, + (const char *) fields[i].org_table, + (const char *) fields[i].db, + (const char *) fields[i].catalog, + (int) fields[i].length, + (int) fields[i].max_length, + (int) fields[i].type, + (int) fields[i].decimals); + + } +} + +static void test_explain_meta() +{ + MYSQL_STMT *stmt; + int num_fields; + char query[MAX_TEST_QUERY_LENGTH]; + MYSQL_RES *rs_metadata; + int rc; + + myheader("test_explain_meta"); + mct_start_logging("test_explain_meta"); + + strmov(query, "SELECT 1"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("SELECT number of fields: %d\n", (int) num_fields); + if (num_fields != 1) + { + mct_close_log(); + DIE("num_fields != 1"); + } + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + strmov(query, "EXPLAIN SELECT 1"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("EXPALIN number of fields: %d\n", (int) num_fields); + if (num_fields != 10) + { + mct_close_log(); + DIE("num_fields != 10"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + strmov(query, "EXPLAIN format=json SELECT 1"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("EXPALIN JSON number of fields: %d\n", (int) num_fields); + if (num_fields != 1) + { + mct_close_log(); + DIE("num_fields != 1"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + + strmov(query, "ANALYZE SELECT 1"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("ANALYZE number of fields: %d\n", (int) num_fields); + if (num_fields != 13) + { + mct_close_log(); + DIE("num_fields != 13"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + strmov(query, "ANALYZE format=json SELECT 1"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("ANALYZE JSON number of fields: %d\n", (int) num_fields); + if (num_fields != 1) + { + mct_close_log(); + DIE("num_fields != 1"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a int)"); + myquery(rc); + + strmov(query, "EXPLAIN INSERT INTO t1 values (1)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("EXPALIN INSERT number of fields: %d\n", (int) num_fields); + if (num_fields != 10) + { + mct_close_log(); + DIE("num_fields != 10"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + strmov(query, "EXPLAIN format=json INSERT INTO t1 values(1)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("EXPALIN JSON INSERT number of fields: %d\n", (int) num_fields); + if (num_fields != 1) + { + mct_close_log(); + DIE("num_fields != 1"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + + strmov(query, "ANALYZE INSERT INTO t1 values(1)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("ANALYZE INSERT number of fields: %d\n", (int) num_fields); + if (num_fields != 13) + { + mct_close_log(); + DIE("num_fields != 13"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + strmov(query, "ANALYZE format=json INSERT INTO t1 values(1)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("ANALYZE JSON INSERT number of fields: %d\n", (int) num_fields); + if (num_fields != 1) + { + mct_close_log(); + DIE("num_fields != 1"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + + strmov(query, "EXPLAIN UPDATE t1 set a=2"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("EXPALIN UPDATE number of fields: %d\n", (int) num_fields); + if (num_fields != 10) + { + mct_close_log(); + DIE("num_fields != 10"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + strmov(query, "EXPLAIN format=json UPDATE t1 set a=2"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("EXPALIN JSON UPDATE number of fields: %d\n", (int) num_fields); + if (num_fields != 1) + { + mct_close_log(); + DIE("num_fields != 1"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + + strmov(query, "ANALYZE UPDATE t1 set a=2"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("ANALYZE UPDATE number of fields: %d\n", (int) num_fields); + if (num_fields != 13) + { + mct_close_log(); + DIE("num_fields != 13"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + strmov(query, "ANALYZE format=json UPDATE t1 set a=2"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("ANALYZE JSON UPDATE number of fields: %d\n", (int) num_fields); + if (num_fields != 1) + { + mct_close_log(); + DIE("num_fields != 1"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + + strmov(query, "EXPLAIN DELETE FROM t1"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("EXPALIN DELETE number of fields: %d\n", (int) num_fields); + if (num_fields != 10) + { + mct_close_log(); + DIE("num_fields != 10"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + strmov(query, "EXPLAIN format=json DELETE FROM t1"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("EXPALIN JSON DELETE number of fields: %d\n", (int) num_fields); + if (num_fields != 1) + { + mct_close_log(); + DIE("num_fields != 1"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + + strmov(query, "ANALYZE DELETE FROM t1"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("ANALYZE DELETE number of fields: %d\n", (int) num_fields); + if (num_fields != 13) + { + mct_close_log(); + DIE("num_fields != 13"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + strmov(query, "ANALYZE format=json DELETE FROM t1"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + mct_log("ANALYZE JSON DELETE number of fields: %d\n", (int) num_fields); + if (num_fields != 1) + { + mct_close_log(); + DIE("num_fields != 1"); + } + print_metadata(rs_metadata, num_fields); + mysql_free_result(rs_metadata); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + mct_close_log(); +} + +static void test_mdev_16128() +{ + int rc, res; + MYSQL_STMT *stmt; + MYSQL_BIND bind, bind_res; + char bind_arg_1[]="d", bind_arg_2[]="b"; + ulong length= 0; + const char *query= + "SELECT 300 FROM t1 WHERE EXISTS (SELECT 100 FROM t2 WHERE t2.b = ?)"; + + myheader("test_mdev_16128"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t2"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a VARCHAR(10))"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2 (b VARCHAR(10) CHARACTER SET utf8)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES('b')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t2 VALUES('d')"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + memset(&bind, 0, sizeof(bind)); + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer_length= strlen(bind_arg_1); + bind.buffer= bind_arg_1; + + rc= mysql_stmt_bind_param(stmt, &bind); + check_execute(stmt, rc); + + memset(&bind_res, 0, sizeof(bind_res)); + bind_res.buffer_type= MYSQL_TYPE_LONG; + bind_res.buffer= &res; + bind_res.is_null= NULL; + bind_res.length= &length; + + rc= mysql_stmt_bind_result(stmt, &bind_res); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + + /** + It's expected that the query + SELECT 300 FROM t1 WHERE EXISTS (SELECT 100 FROM t2 WHERE t2.b = ?)" + executed in PS-mode and bound with the value 'd' returns exactly + one row containing the value (300). + */ + check_execute(stmt, rc); + DIE_UNLESS(bind_res.buffer_type == MYSQL_TYPE_LONG); + DIE_UNLESS(res == 300); + + memset(&bind, 0, sizeof(bind)); + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer_length= strlen(bind_arg_2); + bind.buffer= bind_arg_2; + + rc= mysql_stmt_bind_param(stmt, &bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + /** + It's expected that the query + SELECT 300 FROM t1 WHERE EXISTS (SELECT 100 FROM t2 WHERE t2.b = ?)" + executed in PS-mode and bound with the value 'd' returns empty result set. + */ + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + myquery(rc); +} + +#ifndef EMBEDDED_LIBRARY +#define MDEV19838_MAX_PARAM_COUNT 32 +#define MDEV19838_FIELDS_COUNT 17 +static void test_mdev19838() +{ + int rc; + MYSQL_BIND bind[MDEV19838_MAX_PARAM_COUNT]; + unsigned int i, paramCount = 1; + char charvalue[] = "012345678901234567890123456789012345"; + MYSQL_STMT *stmt; + + myheader("test_mdev19838"); + + rc = mysql_query(mysql, "CREATE TABLE mdev19838(" + "f1 char(36)," + "f2 char(36)," + "f3 char(36)," + "f4 char(36)," + "f5 char(36)," + "f6 char(36)," + "f7 char(36)," + "f8 char(36)," + "f9 char(36)," + "f10 char(36)," + "f11 char(36)," + "f12 char(36)," + "f13 char(36)," + "f14 char(36)," + "f15 char(36)," + "f16 char(36)," + "f17 char(36)" + ")"); + myquery(rc); + + stmt = mysql_stmt_init(mysql); + check_stmt(stmt); + + memset(bind, 0, sizeof(bind)); + + for (i = 0; i < MDEV19838_MAX_PARAM_COUNT; ++i) + { + bind[i].buffer = charvalue; + bind[i].buffer_type = MYSQL_TYPE_STRING; + bind[i].buffer_length = strlen(charvalue) + 1; + bind[i].length = &bind[i].length_value; + bind[i].length_value = bind[i].buffer_length - 1; + } + + for (paramCount = 1; paramCount < MDEV19838_FIELDS_COUNT; ++paramCount) + { + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + + rc = mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17)" + " VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1); + + /* Expecting an error */ + DIE_UNLESS(rc != 0); + + mysql_stmt_close(stmt); + stmt = mysql_stmt_init(mysql); + check_stmt(stmt); + } + + paramCount = 0; + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838(f1)" + " VALUES (?)", -1); + /* Expecting an error */ + DIE_UNLESS(rc != 0); + mysql_stmt_close(stmt); + + stmt = mysql_stmt_init(mysql); + check_stmt(stmt); + /* Correct number of parameters */ + paramCount = MDEV19838_FIELDS_COUNT; + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + mysql_stmt_bind_param(stmt, bind); + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17)" + " VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1); + check_execute(stmt, rc); + + /* MYSQL_TYPE_TINY = 1. This parameter byte can be read as "parameters send" flag byte. + Checking that wrong packet is still detected */ + bind[0].buffer_type = MYSQL_TYPE_TINY; + bind[0].length_value = 1; + bind[0].buffer_length = 1; + + for (paramCount = 8; paramCount > 0; --paramCount) + { + mysql_stmt_close(stmt); + stmt = mysql_stmt_init(mysql); + check_stmt(stmt); + + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + + rc = mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1, f2, f3, f4, f5, f6, f7, f8, f9)" + " VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?)", -1); + + /* Expecting an error */ + DIE_UNLESS(rc != 0); + } + + /* Test of query w/out parameters, with parameter sent and not sent */ + for (paramCount = MDEV19838_MAX_PARAM_COUNT; paramCount != (unsigned int)-1; --paramCount) + { + mysql_stmt_close(stmt); + stmt = mysql_stmt_init(mysql); + check_stmt(stmt); + + mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mCount); + + if (paramCount > 0) + { + rc = mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + } + + rc = mariadb_stmt_execute_direct(stmt, "INSERT INTO mdev19838" + "(f1)" + " VALUES " + "(0x1111111111111111)", -1); + + /* + We allow junk at the end of the packet in case of + no parameters. So it will succeed. + */ + DIE_UNLESS(rc == 0); + } + + mysql_stmt_close(stmt); + + rc = mysql_query(mysql, "drop table mdev19838"); + myquery(rc); +} +#endif // EMBEDDED_LIBRARY + + +/* + MDEV-20261 NULL passed to String::eq, SEGV, server crash, regression in 10.4 +*/ +static void test_mdev20261() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_BIND param[1]; + const char *query= "SELECT * FROM t1 WHERE f = ? OR f = 'foo'"; + char val[]= ""; + my_bool is_null= TRUE; + + myheader("test_mdev20261"); + + rc= mysql_query(mysql, "CREATE OR REPLACE TABLE t1 (f varchar(64)) ENGINE=MyISAM"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + verify_param_count(stmt, 1); + + bzero((char*) param, sizeof(param)); + + param[0].buffer= &val; + param[0].buffer_type= MYSQL_TYPE_STRING; + param[0].is_null= &is_null; + + rc= mysql_stmt_bind_param(stmt, param); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + +static void test_mdev_30159() +{ + MYSQL_RES *result; + int rc; + + myheader("test_mdev_30159"); + + rc= mysql_query(mysql, "create table t1 (" + " name varchar(100)," + " typ varchar(100)" + ")"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5)," + "(6,6),(7,7),(8,8),(9,9),(10,10)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values ('', 'value'),('', 'value')"); + myquery(rc); + rc= mysql_query(mysql, "create table t2 (" + " servername varchar(100)" + ")"); + myquery(rc); + rc= mysql_query(mysql, "insert into t2 values (1),(2),(3),(4),(5)," + "(6),(7),(8),(9),(10)"); + myquery(rc); + rc= mysql_query(mysql, "create view v1 as" + " select * from t2" + " where" + " `t2`.`servername` regexp ( select" + " group_concat(`t1`.`name` separator '|')" + " from `t1`" + " where `t1`.`typ`" + " like 'value')"); + myquery(rc); + + result= mysql_list_fields(mysql, "v1", NULL); + mytest(result); + mysql_free_result(result); + + rc= mysql_query(mysql, "drop view v1"); + myquery(rc); + rc= mysql_query(mysql, "drop table t1, t2"); + myquery(rc); +} + +static void test_execute_direct() +{ +#ifndef EMBEDDED_LIBRARY + MYSQL_STMT* stmt= mysql_stmt_init(mysql); + int rc= mariadb_stmt_execute_direct(stmt,"do 1",-1); + myquery(rc); + mysql_stmt_close(stmt); +#endif +} + + +static void assert_metadata_skipped_count_equals(MYSQL *mysql, int val) +{ + MYSQL_ROW row; + MYSQL_RES *result; + int rc= mysql_query(mysql, "SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE " + "VARIABLE_NAME='Resultset_metadata_skipped'"); + myquery(rc); + result= mysql_use_result(mysql); + mytest(result); + row= mysql_fetch_row(result); + DIE_UNLESS(atoi(row[0]) == val); + mysql_free_result(result); +} + + +static void flush_session_status(MYSQL* mysql) +{ + int rc= mysql_query(mysql, "flush status"); + myquery(rc); +} + + +static void exec_stmt(MYSQL_STMT* stmt) +{ + int rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); +} + + + +static void test_cache_metadata() +{ + char char_val[]= "blah"; + int int_val = 1; + int rc; + MYSQL_BIND param= {0}; + my_bool is_null= FALSE; + + + MYSQL_STMT* stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + rc= mysql_stmt_prepare(stmt, "SELECT ?", -1); + myquery(rc); + + param.buffer= char_val; + param.buffer_type= MYSQL_TYPE_STRING; + param.is_null= &is_null; + param.buffer_length = 4; + + rc= mysql_stmt_bind_param(stmt,¶m); + exec_stmt(stmt); + + flush_session_status(mysql); + /* Execute the statement again, check that metadata is skipped*/ + exec_stmt(stmt); + assert_metadata_skipped_count_equals(mysql, 1); + + flush_session_status(mysql); + /* + Execute the statement again, such that metadata changes, + (using LONG parameter in bind for "SELECT ?", instead of string. + Check that metadata is NOT skipped. + */ + param.buffer= &int_val; + param.buffer_type= MYSQL_TYPE_LONG; + param.is_null= &is_null; + rc= mysql_stmt_bind_param(stmt, ¶m); + exec_stmt(stmt); + assert_metadata_skipped_count_equals(mysql, 0); + mysql_stmt_close(stmt); + + + /* + Test with real table, and DDL which causes column info to be + changed. + */ + stmt= mysql_stmt_init(mysql); + + rc= mysql_query( + mysql, "CREATE OR REPLACE TABLE t1 (a int, b bigint) engine=memory"); + myquery(rc); + + flush_session_status(mysql); + check_stmt(stmt); + rc= mysql_stmt_prepare(stmt, "SELECT * from t1", -1); + myquery(rc); + + exec_stmt(stmt); + /* Metadata skipped, since already sent with COM_STMT_PREPARE result.*/ + assert_metadata_skipped_count_equals(mysql, 1); + + flush_session_status(mysql); + exec_stmt(stmt); + /* Metadata skipped again*/ + assert_metadata_skipped_count_equals(mysql, 1); + + rc= mysql_query(mysql, "ALTER TABLE t1 MODIFY b CHAR(10)"); + myquery(rc); + + /* Column metadata WILL change for the next execution due to DDL*/ + flush_session_status(mysql); + exec_stmt(stmt); + assert_metadata_skipped_count_equals(mysql, 0); + + /* On reexecution, PS column metadata will NOT change. */ + flush_session_status(mysql); + exec_stmt(stmt); + assert_metadata_skipped_count_equals(mysql, 1); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + mysql_stmt_close(stmt); +} + +void test_mdev_10075() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_RES *result; + MYSQL_BIND my_bind[1]; + MYSQL_BIND my_bind2[1]; + + struct st_data { + unsigned long id; + char id_ind; + }; + + struct st_data data[]= { + {0, STMT_INDICATOR_NONE}, + {1, STMT_INDICATOR_NONE}, + {2, STMT_INDICATOR_NONE} + }; + + struct st_data data2[]= { + {3, STMT_INDICATOR_NONE}, + {2, STMT_INDICATOR_NONE}, + {4, STMT_INDICATOR_NONE} + }; + + myheader("test_mdev_10075"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1(id INT PRIMARY KEY)"); + myquery(rc); + + /* insert by prepare */ + stmt= mysql_simple_prepare(mysql, + "INSERT INTO t1 VALUES(?)"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + /* bzero bind structure */ + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_LONG; + my_bind[0].buffer= (void *)&data[0].id; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + /* Set array size, row size and bind the parameter */ + mysql_stmt_bind_param(stmt, my_bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, + "INSERT IGNORE INTO t1 VALUES(?)"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + /* bzero bind structure */ + bzero((char*) my_bind2, sizeof(my_bind2)); + my_bind2[0].buffer_type= MYSQL_TYPE_LONG; + my_bind2[0].buffer= (void *)&data2[0].id; + + rc= mysql_stmt_bind_param(stmt, my_bind2); + check_execute(stmt, rc); + + mysql_stmt_bind_param(stmt, my_bind2); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "GET DIAGNOSTICS CONDITION 1 @var1 = ROW_NUMBER"); + myquery(rc); + + rc= mysql_query(mysql, "SELECT @var1"); + myquery(rc); + + result= mysql_store_result(mysql); + mytest(result); + + rc= my_process_result_set(result); + DIE_UNLESS(rc == 1); + + mysql_free_result(result); +} + +static struct my_tests_st my_tests[]= { + { "test_mdev_20516", test_mdev_20516 }, + { "test_mdev24827", test_mdev24827 }, + { "test_mdev_26145", test_mdev_26145 }, + { "disable_query_logs", disable_query_logs }, + { "test_view_sp_list_fields", test_view_sp_list_fields }, + { "client_query", client_query }, + { "test_prepare_insert_update", test_prepare_insert_update}, +#ifdef EMBEDDED_LIBRARY + { "test_embedded_start_stop", test_embedded_start_stop }, +#endif +#ifdef NOT_YET_WORKING + { "test_drop_temp", test_drop_temp }, +#endif + { "test_fetch_seek", test_fetch_seek }, + { "test_fetch_nobuffs", test_fetch_nobuffs }, + { "test_open_direct", test_open_direct }, + { "test_fetch_null", test_fetch_null }, + { "test_ps_null_param", test_ps_null_param }, + { "test_fetch_date", test_fetch_date }, + { "test_fetch_str", test_fetch_str }, + { "test_fetch_long", test_fetch_long }, + { "test_fetch_short", test_fetch_short }, + { "test_fetch_tiny", test_fetch_tiny }, + { "test_fetch_bigint", test_fetch_bigint }, + { "test_fetch_float", test_fetch_float }, + { "test_fetch_double", test_fetch_double }, + { "test_bind_result_ext", test_bind_result_ext }, + { "test_bind_result_ext1", test_bind_result_ext1 }, + { "test_select_direct", test_select_direct }, + { "test_select_prepare", test_select_prepare }, + { "test_select", test_select }, + { "test_select_version", test_select_version }, + { "test_ps_conj_select", test_ps_conj_select }, + { "test_select_show_table", test_select_show_table }, + { "test_func_fields", test_func_fields }, + { "test_long_data", test_long_data }, + { "test_insert", test_insert }, + { "test_set_variable", test_set_variable }, + { "test_select_show", test_select_show }, + { "test_prepare_noparam", test_prepare_noparam }, + { "test_bind_result", test_bind_result }, + { "test_prepare_simple", test_prepare_simple }, + { "test_prepare", test_prepare }, + { "test_null", test_null }, + { "test_debug_example", test_debug_example }, + { "test_update", test_update }, + { "test_simple_update", test_simple_update }, + { "test_simple_delete", test_simple_delete }, + { "test_double_compare", test_double_compare }, + { "client_store_result", client_store_result }, + { "client_use_result", client_use_result }, + { "test_tran_bdb", test_tran_bdb }, + { "test_tran_innodb", test_tran_innodb }, + { "test_prepare_ext", test_prepare_ext }, + { "test_prepare_syntax", test_prepare_syntax }, + { "test_field_names", test_field_names }, + { "test_field_flags", test_field_flags }, + { "test_long_data_str", test_long_data_str }, + { "test_long_data_str1", test_long_data_str1 }, + { "test_long_data_bin", test_long_data_bin }, + { "test_warnings", test_warnings }, + { "test_errors", test_errors }, + { "test_prepare_resultset", test_prepare_resultset }, + { "test_stmt_close", test_stmt_close }, + { "test_prepare_field_result", test_prepare_field_result }, + { "test_multi_stmt", test_multi_stmt }, + { "test_multi_statements", test_multi_statements }, + { "test_prepare_multi_statements", test_prepare_multi_statements }, + { "test_store_result", test_store_result }, + { "test_store_result1", test_store_result1 }, + { "test_store_result2", test_store_result2 }, + { "test_subselect", test_subselect }, + { "test_date", test_date }, + { "test_simple_temporal", test_simple_temporal }, + { "test_date_date", test_date_date }, + { "test_date_time", test_date_time }, + { "test_date_ts", test_date_ts }, + { "test_date_dt", test_date_dt }, + { "test_prepare_alter", test_prepare_alter }, + { "test_manual_sample", test_manual_sample }, + { "test_pure_coverage", test_pure_coverage }, + { "test_buffers", test_buffers }, + { "test_ushort_bug", test_ushort_bug }, + { "test_sshort_bug", test_sshort_bug }, + { "test_stiny_bug", test_stiny_bug }, + { "test_field_misc", test_field_misc }, + { "test_set_option", test_set_option }, +#ifndef EMBEDDED_LIBRARY + { "test_prepare_grant", test_prepare_grant }, + +#endif + { "test_frm_bug", test_frm_bug }, + { "test_explain_bug", test_explain_bug }, + { "test_decimal_bug", test_decimal_bug }, + { "test_nstmts", test_nstmts }, + { "test_logs;", test_logs }, + { "test_cuted_rows", test_cuted_rows }, + { "test_fetch_offset", test_fetch_offset }, + { "test_fetch_column", test_fetch_column }, + { "test_mem_overun", test_mem_overun }, + { "test_list_fields", test_list_fields }, + { "test_list_information_schema_fields", test_list_information_schema_fields }, + { "test_list_fields_blob", test_list_fields_blob }, + { "test_list_fields_default", test_list_fields_default }, + { "test_free_result", test_free_result }, + { "test_free_store_result", test_free_store_result }, + { "test_sqlmode", test_sqlmode }, + { "test_ts", test_ts }, + { "test_bug1115", test_bug1115 }, + { "test_bug1180", test_bug1180 }, + { "test_bug1500", test_bug1500 }, + { "test_bug1644", test_bug1644 }, + { "test_bug1946", test_bug1946 }, + { "test_bug2248", test_bug2248 }, + { "test_parse_error_and_bad_length", test_parse_error_and_bad_length }, + { "test_bug2247", test_bug2247 }, + { "test_subqueries", test_subqueries }, + { "test_bad_union", test_bad_union }, + { "test_distinct", test_distinct }, + { "test_subqueries_ref", test_subqueries_ref }, + { "test_union", test_union }, + { "test_bug3117", test_bug3117 }, + { "test_join", test_join }, + { "test_selecttmp", test_selecttmp }, + { "test_create_drop", test_create_drop }, + { "test_rename", test_rename }, + { "test_do_set", test_do_set }, + { "test_multi", test_multi }, + { "test_insert_select", test_insert_select }, + { "test_bind_nagative", test_bind_nagative }, + { "test_derived", test_derived }, + { "test_xjoin", test_xjoin }, + { "test_bug3035", test_bug3035 }, + { "test_union2", test_union2 }, + { "test_bug1664", test_bug1664 }, + { "test_union_param", test_union_param }, + { "test_order_param", test_order_param }, + { "test_ps_i18n", test_ps_i18n }, + { "test_bug3796", test_bug3796 }, + { "test_bug4026", test_bug4026 }, + { "test_bug4079", test_bug4079 }, + { "test_bug4236", test_bug4236 }, + { "test_bug4030", test_bug4030 }, + { "test_bug5126", test_bug5126 }, + { "test_bug4231", test_bug4231 }, + { "test_bug5399", test_bug5399 }, + { "test_bug5194", test_bug5194 }, + { "test_bug5315", test_bug5315 }, + { "test_bug6049", test_bug6049 }, + { "test_bug6058", test_bug6058 }, + { "test_bug6059", test_bug6059 }, + { "test_bug6046", test_bug6046 }, + { "test_bug6081", test_bug6081 }, + { "test_bug6096", test_bug6096 }, + { "test_datetime_ranges", test_datetime_ranges }, + { "test_datetime_ranges_mdev15289", test_datetime_ranges_mdev15289 }, + { "test_bug4172", test_bug4172 }, + { "test_conversion", test_conversion }, + { "test_rewind", test_rewind }, + { "test_bug6761", test_bug6761 }, + { "test_view", test_view }, + { "test_view_where", test_view_where }, + { "test_view_2where", test_view_2where }, + { "test_view_star", test_view_star }, + { "test_view_insert", test_view_insert }, + { "test_left_join_view", test_left_join_view }, + { "test_view_insert_fields", test_view_insert_fields }, + { "test_basic_cursors", test_basic_cursors }, + { "test_cursors_with_union", test_cursors_with_union }, + { "test_cursors_with_procedure", test_cursors_with_procedure }, + { "test_truncation", test_truncation }, + { "test_truncation_option", test_truncation_option }, + { "test_client_character_set", test_client_character_set }, + { "test_bug8330", test_bug8330 }, + { "test_bug7990", test_bug7990 }, + { "test_bug8378", test_bug8378 }, + { "test_bug8722", test_bug8722 }, + { "test_bug8880", test_bug8880 }, + { "test_open_cursor_prepared_statement_query_cache", + test_open_cursor_prepared_statement_query_cache }, + { "test_bug9159", test_bug9159 }, + { "test_bug9520", test_bug9520 }, + { "test_bug9478", test_bug9478 }, + { "test_bug9643", test_bug9643 }, + { "test_bug10729", test_bug10729 }, + { "test_bug11111", test_bug11111 }, + { "test_bug9992", test_bug9992 }, + { "test_bug10736", test_bug10736 }, + { "test_bug10794", test_bug10794 }, + { "test_bug11172", test_bug11172 }, + { "test_bug11656", test_bug11656 }, + { "test_bug10214", test_bug10214 }, + { "test_bug9735", test_bug9735 }, + { "test_bug11183", test_bug11183 }, + { "test_bug11037", test_bug11037 }, + { "test_bug10760", test_bug10760 }, + { "test_bug12001", test_bug12001 }, + { "test_bug11718", test_bug11718 }, + { "test_bug12925", test_bug12925 }, + { "test_bug11909", test_bug11909 }, + { "test_bug11901", test_bug11901 }, + { "test_bug11904", test_bug11904 }, + { "test_bug12243", test_bug12243 }, + { "test_bug14210", test_bug14210 }, + { "test_bug13488", test_bug13488 }, + { "test_bug13524", test_bug13524 }, + { "test_bug14845", test_bug14845 }, + { "test_opt_reconnect", test_opt_reconnect }, + { "test_bug15510", test_bug15510}, +#ifndef EMBEDDED_LIBRARY + { "test_bug12744", test_bug12744 }, +#endif + { "test_bug16143", test_bug16143 }, + { "test_bug16144", test_bug16144 }, + { "test_bug15613", test_bug15613 }, + { "test_bug20152", test_bug20152 }, + { "test_bug14169", test_bug14169 }, + { "test_bug17667", test_bug17667 }, + { "test_bug15752", test_bug15752 }, + { "test_mysql_insert_id", test_mysql_insert_id }, + { "test_bug19671", test_bug19671 }, + { "test_bug21206", test_bug21206 }, + { "test_bug21726", test_bug21726 }, + { "test_bug15518", test_bug15518 }, + { "test_bug23383", test_bug23383 }, + { "test_bug32265", test_bug32265 }, + { "test_bug21635", test_bug21635 }, + { "test_status", test_status }, + { "test_bug24179", test_bug24179 }, + { "test_ps_query_cache", test_ps_query_cache }, + { "test_bug28075", test_bug28075 }, + { "test_bug27876", test_bug27876 }, + { "test_bug28505", test_bug28505 }, + { "test_bug28934", test_bug28934 }, + { "test_bug27592", test_bug27592 }, + { "test_bug29687", test_bug29687 }, + { "test_bug29692", test_bug29692 }, + { "test_bug29306", test_bug29306 }, + { "test_change_user", test_change_user }, + { "test_bug30472", test_bug30472 }, + { "test_bug20023", test_bug20023 }, + { "test_bug45010", test_bug45010 }, + { "test_bug53371", test_bug53371 }, + { "test_bug31418", test_bug31418 }, + { "test_bug31669", test_bug31669 }, + { "test_bug28386", test_bug28386 }, + { "test_wl4166_1", test_wl4166_1 }, + { "test_wl4166_2", test_wl4166_2 }, + { "test_wl4166_3", test_wl4166_3 }, + { "test_wl4166_4", test_wl4166_4 }, + { "test_bug36004", test_bug36004 }, + { "test_wl4284_1", test_wl4284_1 }, + { "test_wl4435", test_wl4435 }, + { "test_wl4435_2", test_wl4435_2 }, + { "test_wl4435_3", test_wl4435_3 }, + { "test_bug38486", test_bug38486 }, + { "test_bug33831", test_bug33831 }, + { "test_bug40365", test_bug40365 }, + { "test_bug43560", test_bug43560 }, + { "test_bug36326", test_bug36326 }, + { "test_bug41078", test_bug41078 }, + { "test_bug44495", test_bug44495 }, + { "test_bug49972", test_bug49972 }, + { "test_bug42373", test_bug42373 }, + { "test_bug54041", test_bug54041 }, + { "test_bug47485", test_bug47485 }, + { "test_bug58036", test_bug58036 }, + { "test_bug57058", test_bug57058 }, + { "test_bug56976", test_bug56976 }, + { "test_mdev3885", test_mdev3885 }, + { "test_mdev4603", test_mdev4603 }, + { "test_bug11766854", test_bug11766854 }, + { "test_bug12337762", test_bug12337762 }, + { "test_progress_reporting", test_progress_reporting }, + { "test_bug11754979", test_bug11754979 }, + { "test_bug13001491", test_bug13001491 }, + { "test_mdev4326", test_mdev4326 }, + { "test_ps_sp_out_params", test_ps_sp_out_params }, +#ifndef _WIN32 + { "test_bug17512527", test_bug17512527}, +#endif + { "test_compressed_protocol", test_compressed_protocol }, + { "test_big_packet", test_big_packet }, + { "test_prepare_analyze", test_prepare_analyze }, + { "test_mdev12579", test_mdev12579 }, + { "test_mdev14013", test_mdev14013 }, + { "test_mdev14013_1", test_mdev14013_1 }, + { "test_mdev14454", test_mdev14454 }, +#ifndef EMBEDDED_LIBRARY + { "test_proxy_header", test_proxy_header}, + { "test_bulk_autoinc", test_bulk_autoinc}, + { "test_bulk_delete", test_bulk_delete }, + { "test_bulk_replace", test_bulk_replace }, + { "test_bulk_insert_returning", test_bulk_insert_returning }, + { "test_bulk_delete_returning", test_bulk_delete_returning }, +#endif + { "test_ps_params_in_ctes", test_ps_params_in_ctes }, + { "test_explain_meta", test_explain_meta }, +#ifndef EMBEDDED_LIBRARY + { "test_mdev19838", test_mdev19838 }, +#endif + { "test_mdev_16128", test_mdev_16128 }, + { "test_mdev18408", test_mdev18408 }, + { "test_mdev20261", test_mdev20261 }, + { "test_mdev_30159", test_mdev_30159 }, + { "test_execute_direct", test_execute_direct }, + { "test_cache_metadata", test_cache_metadata}, + { "test_mdev_10075", test_mdev_10075}, + { 0, 0 } +}; + + +static struct my_tests_st *get_my_tests() { return my_tests; } |