diff options
author | unknown <jimw@mysql.com> | 2005-01-24 13:48:48 -0800 |
---|---|---|
committer | unknown <jimw@mysql.com> | 2005-01-24 13:48:48 -0800 |
commit | c312cf2762cfc68abaebd87294331f599a522436 (patch) | |
tree | c3a261433ebe14a453233665edd8251485c39c4a /tests/mysql_client_test.c | |
parent | 712f3f677b97a89bc1a2ff6a67cbda00a2be25ca (diff) | |
parent | 844fe1ea6d8a14d04e78751be1e77838aa2bbd7d (diff) | |
download | mariadb-git-c312cf2762cfc68abaebd87294331f599a522436.tar.gz |
Merge
BitKeeper/etc/ignore:
auto-union
include/my_global.h:
Auto merged
libmysql/libmysql.c:
Auto merged
libmysqld/examples/Makefile.am:
Auto merged
scripts/make_binary_distribution.sh:
Auto merged
sql/mysqld.cc:
Auto merged
tests/mysql_client_test.c:
Auto merged
Diffstat (limited to 'tests/mysql_client_test.c')
-rw-r--r-- | tests/mysql_client_test.c | 12884 |
1 files changed, 12884 insertions, 0 deletions
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c new file mode 100644 index 00000000000..3cbc9918d6c --- /dev/null +++ b/tests/mysql_client_test.c @@ -0,0 +1,12884 @@ +/* Copyright (C) 2003-2004 MySQL AB + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. +*/ + + +#include <my_global.h> +#include <my_sys.h> +#include <mysql.h> +#include <my_getopt.h> +#include <m_string.h> + +#define VER "2.1" +#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ +#define MAX_KEY 64 + +/* set default options */ +static int opt_testcase = 0; +static char *opt_db= 0; +static char *opt_user= 0; +static char *opt_password= 0; +static char *opt_host= 0; +static char *opt_unix_socket= 0; +static unsigned int opt_port; +static my_bool tty_password= 0, opt_silent= 0; + +static MYSQL *mysql= 0; +static char query[MAX_TEST_QUERY_LENGTH]; +static char current_db[]= "client_test_db"; +static unsigned int test_count= 0; +static unsigned int opt_count= 0; +static unsigned int iter_count= 0; + +static time_t start_time, end_time; +static double total_time; + +const char *default_dbug_option= "d:t:o,/tmp/client_test.trace"; + +struct my_tests_st +{ + const char *name; + void (*function)(); +}; + +#define myheader(str) \ +if (opt_silent < 2) \ +{ \ + fprintf(stdout, "\n\n#####################################\n"); \ + fprintf(stdout, "%d of (%d/%d): %s", test_count++, iter_count, \ + opt_count, str); \ + fprintf(stdout, " \n#####################################\n"); \ +} +#define myheader_r(str) \ +if (!opt_silent) \ +{ \ + fprintf(stdout, "\n\n#####################################\n"); \ + fprintf(stdout, "%s", str); \ + fprintf(stdout, " \n#####################################\n"); \ +} + +static void print_error(const char *msg); +static void print_st_error(MYSQL_STMT *stmt, const char *msg); +static void client_disconnect(); + + +/* + Abort unless given experssion is non-zero. + + SYNOPSIS + DIE_UNLESS(expr) + + DESCRIPTION + We can't use any kind of system assert as we need to + preserve tested invariants in release builds as well. +*/ + +#define DIE_UNLESS(expr) \ + ((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) + +void die(const char *file, int line, const char *expr) +{ + fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); + abort(); +} + + +#define myerror(msg) print_error(msg) +#define mysterror(stmt, msg) print_st_error(stmt, msg) + +#define myquery(RES) \ +{ \ + int r= (RES); \ + if (r) \ + myerror(NULL); \ + DIE_UNLESS(r == 0); \ +} + +#define myquery_r(r) \ +{ \ +if (r) \ + myerror(NULL); \ +DIE_UNLESS(r != 0); \ +} + +#define check_execute(stmt, r) \ +{ \ +if (r) \ + mysterror(stmt, NULL); \ +DIE_UNLESS(r == 0);\ +} + +#define check_execute_r(stmt, r) \ +{ \ +if (r) \ + mysterror(stmt, NULL); \ +DIE_UNLESS(r != 0);\ +} + +#define check_stmt(stmt) \ +{ \ +if ( stmt == 0) \ + myerror(NULL); \ +DIE_UNLESS(stmt != 0); \ +} + +#define check_stmt_r(stmt) \ +{ \ +if (stmt == 0) \ + myerror(NULL);\ +DIE_UNLESS(stmt == 0);\ +} + +#define mytest(x) if (!x) {myerror(NULL);DIE_UNLESS(FALSE);} +#define mytest_r(x) if (x) {myerror(NULL);DIE_UNLESS(FALSE);} + + +/* Print the error message */ + +static void print_error(const char *msg) +{ + if (!opt_silent) + { + if (mysql && mysql_errno(mysql)) + { + 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)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); + } +} + + +static void print_st_error(MYSQL_STMT *stmt, const char *msg) +{ + if (!opt_silent) + { + if (stmt && mysql_stmt_errno(stmt)) + { + if (stmt->mysql && stmt->mysql->server_version) + fprintf(stdout, "\n [MySQL-%s]", stmt->mysql->server_version); + else + fprintf(stdout, "\n [MySQL]"); + + fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); + } +} + + +/* + This is to be what mysql_query() is for mysql_real_query(), for + mysql_simple_prepare(): a variant without the 'length' parameter. +*/ + +MYSQL_STMT *STDCALL +mysql_simple_prepare(MYSQL *mysql, const char *query) +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + if (stmt && mysql_stmt_prepare(stmt, query, strlen(query))) + { + mysql_stmt_close(stmt); + return 0; + } + return stmt; +} + + +/* Connect to the server */ + +static void client_connect() +{ + int rc; + myheader_r("client_connect"); + + if (!opt_silent) + fprintf(stdout, "\n Establishing a connection to '%s' ...", + opt_host ? opt_host : ""); + + if (!(mysql= mysql_init(NULL))) + { + opt_silent= 0; + myerror("mysql_init() failed"); + exit(1); + } + + if (!(mysql_real_connect(mysql, opt_host, opt_user, + opt_password, opt_db ? opt_db:"test", opt_port, + opt_unix_socket, 0))) + { + opt_silent= 0; + myerror("connection failed"); + mysql_close(mysql); + fprintf(stdout, "\n Check the connection options using --help or -?\n"); + exit(1); + } + mysql->reconnect= 1; + + if (!opt_silent) + fprintf(stdout, " OK"); + + /* set AUTOCOMMIT to ON*/ + mysql_autocommit(mysql, TRUE); + + if (!opt_silent) + fprintf(stdout, "\n Creating a test database '%s' ...", current_db); + strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS); + + rc= mysql_query(mysql, query); + myquery(rc); + + strxmov(query, "USE ", current_db, NullS); + rc= mysql_query(mysql, query); + myquery(rc); + + if (!opt_silent) + fprintf(stdout, " OK"); +} + + +/* Close the connection */ + +static void client_disconnect() +{ + myheader_r("client_disconnect"); + + if (mysql) + { + if (!opt_silent) + fprintf(stdout, "\n dropping the test database '%s' ...", current_db); + strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS); + + mysql_query(mysql, query); + if (!opt_silent) + fprintf(stdout, " OK"); + + if (!opt_silent) + fprintf(stdout, "\n closing the connection ..."); + mysql_close(mysql); + fprintf(stdout, " OK\n"); + } +} + + +/* Query processing */ + +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")); +} + + +/* Print dashes */ + +static void my_print_dashes(MYSQL_RES *result) +{ + MYSQL_FIELD *field; + unsigned int i, j; + + mysql_field_seek(result, 0); + fputc('\t', stdout); + fputc('+', stdout); + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + for(j= 0; j < field->max_length+2; j++) + fputc('-', stdout); + fputc('+', stdout); + } + fputc('\n', stdout); +} + + +/* Print resultset metadata information */ + +static void my_print_result_metadata(MYSQL_RES *result) +{ + MYSQL_FIELD *field; + unsigned int i, j; + unsigned int field_count; + + mysql_field_seek(result, 0); + if (!opt_silent) + { + fputc('\n', stdout); + fputc('\n', stdout); + } + + field_count= mysql_num_fields(result); + for(i= 0; i< field_count; i++) + { + field= mysql_fetch_field(result); + j= strlen(field->name); + if (j < field->max_length) + j= field->max_length; + if (j < 4 && !IS_NOT_NULL(field->flags)) + j= 4; + field->max_length= j; + } + if (!opt_silent) + { + my_print_dashes(result); + fputc('\t', stdout); + fputc('|', stdout); + } + + mysql_field_seek(result, 0); + for(i= 0; i< field_count; i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + fprintf(stdout, " %-*s |", (int) field->max_length, field->name); + } + if (!opt_silent) + { + fputc('\n', stdout); + my_print_dashes(result); + } +} + + +/* Process the result set */ + +int my_process_result_set(MYSQL_RES *result) +{ + MYSQL_ROW row; + MYSQL_FIELD *field; + unsigned int i; + unsigned int row_count= 0; + + if (!result) + return 0; + + my_print_result_metadata(result); + + while ((row= mysql_fetch_row(result)) != NULL) + { + mysql_field_seek(result, 0); + if (!opt_silent) + { + fputc('\t', stdout); + fputc('|', stdout); + } + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + if (row[i] == NULL) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, row[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, row[i]); + } + } + if (!opt_silent) + { + fputc('\t', stdout); + fputc('\n', stdout); + } + row_count++; + } + if (!opt_silent) + { + if (row_count) + my_print_dashes(result); + + if (mysql_errno(mysql) != 0) + fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); + else + fprintf(stdout, "\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + } + return row_count; +} + + +int my_process_result(MYSQL *mysql) +{ + MYSQL_RES *result; + int row_count; + + if (!(result= mysql_store_result(mysql))) + return 0; + + row_count= my_process_result_set(result); + + mysql_free_result(result); + return row_count; +} + + +/* Process the statement result set */ + +#define MAX_RES_FIELDS 50 +#define MAX_FIELD_DATA_SIZE 255 + +int my_process_stmt_result(MYSQL_STMT *stmt) +{ + int field_count; + int row_count= 0; + MYSQL_BIND buffer[MAX_RES_FIELDS]; + MYSQL_FIELD *field; + MYSQL_RES *result; + char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE]; + ulong length[MAX_RES_FIELDS]; + my_bool is_null[MAX_RES_FIELDS]; + int rc, i; + + if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */ + { + while (!mysql_stmt_fetch(stmt)) + row_count++; + return row_count; + } + + field_count= min(mysql_num_fields(result), MAX_RES_FIELDS); + + bzero((char*) buffer, sizeof(buffer)); + bzero((char*) length, sizeof(length)); + bzero((char*) is_null, sizeof(is_null)); + + for(i= 0; i < field_count; i++) + { + buffer[i].buffer_type= MYSQL_TYPE_STRING; + buffer[i].buffer_length= MAX_FIELD_DATA_SIZE; + buffer[i].length= &length[i]; + buffer[i].buffer= (void *) data[i]; + buffer[i].is_null= &is_null[i]; + } + + rc= mysql_stmt_bind_result(stmt, buffer); + check_execute(stmt, rc); + + rc= 1; + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc); + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + { + fputc('\t', stdout); + fputc('|', stdout); + } + mysql_field_seek(result, 0); + for (i= 0; i < field_count; i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + if (is_null[i]) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (length[i] == 0) + { + data[i][0]= '\0'; /* unmodified buffer */ + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + } + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); + } + } + if (!opt_silent) + { + fputc('\t', stdout); + fputc('\n', stdout); + } + row_count++; + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + if (!opt_silent) + { + if (row_count) + my_print_dashes(result); + fprintf(stdout, "\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + } + mysql_free_result(result); + return row_count; +} + + +/* Prepare statement, execute, and process result set for given query */ + +int my_stmt_result(const char *buff) +{ + MYSQL_STMT *stmt; + int row_count; + int rc; + + if (!opt_silent) + fprintf(stdout, "\n\n %s", buff); + stmt= mysql_simple_prepare(mysql, buff); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + row_count= my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + + return row_count; +} + + +/* Utility function to verify a particular column data */ + +static void verify_col_data(const char *table, const char *col, + const char *exp_data) +{ + MYSQL_RES *result; + MYSQL_ROW row; + int rc, field= 1; + + if (table && col) + { + strxmov(query, "SELECT ", col, " FROM ", table, " LIMIT 1", NullS); + if (!opt_silent) + fprintf(stdout, "\n %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + field= 0; + } + + result= mysql_use_result(mysql); + mytest(result); + + if (!(row= mysql_fetch_row(result)) || !row[field]) + { + fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + if (strcmp(row[field], exp_data)) + { + fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", + row[field], exp_data); + DIE_UNLESS(FALSE); + } + mysql_free_result(result); +} + + +/* Utility function to verify the field members */ + +static void verify_prepare_field(MYSQL_RES *result, + unsigned int no, const char *name, + const char *org_name, + enum enum_field_types type, + const char *table, + const char *org_table, const char *db, + unsigned long length, const char *def) +{ + MYSQL_FIELD *field; + CHARSET_INFO *cs; + + if (!(field= mysql_fetch_field_direct(result, no))) + { + fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + cs= get_charset(field->charsetnr, 0); + DIE_UNLESS(cs); + if (!opt_silent) + { + fprintf(stdout, "\n field[%d]:", no); + fprintf(stdout, "\n name :`%s`\t(expected: `%s`)", field->name, name); + fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)", + field->org_name, org_name); + fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type); + if (table) + fprintf(stdout, "\n table :`%s`\t(expected: `%s`)", + field->table, table); + if (org_table) + fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", + field->org_table, org_table); + fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); + fprintf(stdout, "\n length :`%ld`\t(expected: `%ld`)", + field->length, length * cs->mbmaxlen); + fprintf(stdout, "\n maxlength:`%ld`", field->max_length); + fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); + fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", + field->def ? field->def : "(null)", def ? def: "(null)"); + fprintf(stdout, "\n"); + } + DIE_UNLESS(strcmp(field->name, name) == 0); + DIE_UNLESS(strcmp(field->org_name, org_name) == 0); + /* + XXX: silent column specification change works based on number of + bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even + for CHAR(2) column if its character set is multibyte. + VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would + expect. + */ + if (cs->mbmaxlen == 1) + { + if (field->type != type) + { + fprintf(stderr, "Expected field type: %d, got type: %d\n", + (int) type, (int) field->type); + DIE_UNLESS(field->type == type); + } + } + if (table) + DIE_UNLESS(strcmp(field->table, table) == 0); + if (org_table) + DIE_UNLESS(strcmp(field->org_table, org_table) == 0); + DIE_UNLESS(strcmp(field->db, db) == 0); + /* + Character set should be taken into account for multibyte encodings, such + as utf8. Field length is calculated as number of characters * maximum + number of bytes a character can occupy. + */ + if (length && field->length != length * cs->mbmaxlen) + { + fprintf(stderr, "Expected field length: %d, got length: %d\n", + (int) (length * cs->mbmaxlen), (int) field->length); + DIE_UNLESS(field->length == length * cs->mbmaxlen); + } + if (def) + DIE_UNLESS(strcmp(field->def, def) == 0); +} + + +/* Utility function to verify the parameter count */ + +static void verify_param_count(MYSQL_STMT *stmt, long exp_count) +{ + long param_count= mysql_stmt_param_count(stmt); + if (!opt_silent) + fprintf(stdout, "\n total parameters in stmt: `%ld` (expected: `%ld`)", + param_count, exp_count); + DIE_UNLESS(param_count == exp_count); +} + + +/* Utility function to verify the total affected rows */ + +static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count) +{ + ulonglong affected_rows= mysql_stmt_affected_rows(stmt); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + DIE_UNLESS(affected_rows == exp_count); +} + + +/* Utility function to verify the total affected rows */ + +static void verify_affected_rows(ulonglong exp_count) +{ + ulonglong affected_rows= mysql_affected_rows(mysql); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + DIE_UNLESS(affected_rows == exp_count); +} + + +/* Utility function to verify the total fields count */ + +static void verify_field_count(MYSQL_RES *result, uint exp_count) +{ + uint field_count= mysql_num_fields(result); + if (!opt_silent) + fprintf(stdout, "\n total fields in the result set: `%d` (expected: `%d`)", + field_count, exp_count); + DIE_UNLESS(field_count == exp_count); +} + + +/* Utility function to execute a query using prepare-execute */ + +static void execute_prepare_query(const char *query, ulonglong exp_count) +{ + MYSQL_STMT *stmt; + ulonglong affected_rows; + int rc; + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + myquery(rc); + + affected_rows= mysql_stmt_affected_rows(stmt); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + + DIE_UNLESS(affected_rows == exp_count); + mysql_stmt_close(stmt); +} + + +/* 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); +} + + +/* + Accepts arbitrary number of queries and runs them against the database. + Used to fill tables for each test. +*/ + +void fill_tables(const char **query_list, unsigned query_count) +{ + int rc; + const char **query; + DBUG_ENTER("fill_tables"); + for (query= query_list; query < query_list + query_count; + ++query) + { + rc= mysql_query(mysql, *query); + myquery(rc); + } + DBUG_VOID_RETURN; +} + +/* + All state of fetch from one statement: statement handle, out buffers, + fetch position. + See fetch_n for for the only use case. +*/ + +enum { MAX_COLUMN_LENGTH= 255 }; + +typedef struct st_stmt_fetch +{ + const char *query; + unsigned stmt_no; + MYSQL_STMT *handle; + my_bool is_open; + MYSQL_BIND *bind_array; + char **out_data; + unsigned long *out_data_length; + unsigned column_count; + unsigned row_count; +} Stmt_fetch; + + +/* + Create statement handle, prepare it with statement, execute and allocate + fetch buffers. +*/ + +void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg, + const char *query_arg) +{ + unsigned long type= CURSOR_TYPE_READ_ONLY; + int rc; + unsigned i; + MYSQL_RES *metadata; + DBUG_ENTER("stmt_fetch_init"); + + /* Save query and statement number for error messages */ + fetch->stmt_no= stmt_no_arg; + fetch->query= query_arg; + + fetch->handle= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query)); + check_execute(fetch->handle, rc); + + /* + The attribute is sent to server on execute and asks to open read-only + for result set + */ + mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE, + (const void*) &type); + + rc= mysql_stmt_execute(fetch->handle); + check_execute(fetch->handle, rc); + + /* Find out total number of columns in result set */ + metadata= mysql_stmt_result_metadata(fetch->handle); + fetch->column_count= mysql_num_fields(metadata); + mysql_free_result(metadata); + + /* + Now allocate bind handles and buffers for output data: + calloc memory to reduce number of MYSQL_BIND members we need to + set up. + */ + + fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) * + fetch->column_count); + fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count); + fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) * + fetch->column_count); + for (i= 0; i < fetch->column_count; ++i) + { + fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH); + fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING; + fetch->bind_array[i].buffer= fetch->out_data[i]; + fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH; + fetch->bind_array[i].length= fetch->out_data_length + i; + } + + mysql_stmt_bind_result(fetch->handle, fetch->bind_array); + + fetch->row_count= 0; + fetch->is_open= TRUE; + + /* Ready for reading rows */ + DBUG_VOID_RETURN; +} + + +/* Fetch and print one row from cursor */ + +int stmt_fetch_fetch_row(Stmt_fetch *fetch) +{ + int rc; + unsigned i; + DBUG_ENTER("stmt_fetch_fetch_row"); + + if ((rc= mysql_stmt_fetch(fetch->handle)) == 0) + { + ++fetch->row_count; + if (!opt_silent) + printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count); + for (i= 0; i < fetch->column_count; ++i) + { + fetch->out_data[i][fetch->out_data_length[i]]= '\0'; + if (!opt_silent) + printf("column %d: %s\n", i+1, fetch->out_data[i]); + } + } + else + fetch->is_open= FALSE; + DBUG_RETURN(rc); +} + + +void stmt_fetch_close(Stmt_fetch *fetch) +{ + unsigned i; + DBUG_ENTER("stmt_fetch_close"); + + for (i= 0; i < fetch->column_count; ++i) + free(fetch->out_data[i]); + free(fetch->out_data); + free(fetch->out_data_length); + free(fetch->bind_array); + mysql_stmt_close(fetch->handle); + DBUG_VOID_RETURN; +} + +/* + For given array of queries, open query_count cursors and fetch + from them in simultaneous manner. + In case there was an error in one of the cursors, continue + reading from the rest. +*/ + +my_bool fetch_n(const char **query_list, unsigned query_count) +{ + unsigned open_statements= query_count; + int rc, error_count= 0; + Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) * + query_count); + Stmt_fetch *fetch; + DBUG_ENTER("fetch_n"); + + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + /* Init will exit(1) in case of error */ + stmt_fetch_init(fetch, fetch - fetch_array, + query_list[fetch - fetch_array]); + } + + while (open_statements) + { + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch))) + { + open_statements--; + /* + We try to fetch from the rest of the statements in case of + error + */ + if (rc != MYSQL_NO_DATA) + { + fprintf(stderr, + "Got error reading rows from statement %d,\n" + "query is: %s,\n" + "error message: %s", (int) (fetch - fetch_array), + fetch->query, + mysql_stmt_error(fetch->handle)); + error_count++; + } + } + } + } + if (error_count) + fprintf(stderr, "Fetch FAILED"); + else + { + unsigned total_row_count= 0; + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + total_row_count+= fetch->row_count; + if (!opt_silent) + printf("Success, total rows fetched: %d\n", total_row_count); + } + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + stmt_fetch_close(fetch); + free(fetch_array); + DBUG_RETURN(error_count != 0); +} + +/* Separate thread query to test some cases */ + +static my_bool thread_query(char *query) +{ + MYSQL *l_mysql; + my_bool error; + + error= 0; + if (!opt_silent) + fprintf(stdout, "\n in thread_query(%s)", query); + if (!(l_mysql= mysql_init(NULL))) + { + myerror("mysql_init() failed"); + return 1; + } + if (!(mysql_real_connect(l_mysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + error= 1; + goto end; + } + l_mysql->reconnect= 1; + if (mysql_query(l_mysql, (char *)query)) + { + fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql)); + error= 1; + goto end; + } + mysql_commit(l_mysql); +end: + mysql_close(l_mysql); + return error; +} + + +/* 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)) TYPE= 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)) TYPE= 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++) + { + 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; + + 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); + + /* now fetch the results ..*/ + rc= mysql_commit(mysql); + myquery(rc); +} + + +/* Test simple prepare field results */ + +static void test_prepare_field_result() +{ + MYSQL_STMT *stmt; + MYSQL_RES *result; + int rc; + + 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(14), " + "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; + + 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 bind[7]; + + 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*) bind, sizeof(bind)); + + /* tinyint */ + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[0].buffer= (void *)&tiny_data; + /* string */ + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (void *)str_data; + bind[1].buffer_length= 1000; /* Max string length */ + /* integer */ + bind[2].buffer_type= MYSQL_TYPE_LONG; + bind[2].buffer= (void *)&int_data; + /* short */ + bind[3].buffer_type= MYSQL_TYPE_SHORT; + bind[3].buffer= (void *)&small_data; + /* bigint */ + bind[4].buffer_type= MYSQL_TYPE_LONGLONG; + bind[4].buffer= (void *)&big_data; + /* float */ + bind[5].buffer_type= MYSQL_TYPE_FLOAT; + bind[5].buffer= (void *)&real_data; + /* double */ + bind[6].buffer_type= MYSQL_TYPE_DOUBLE; + bind[6].buffer= (void *)&double_data; + + for (i= 0; i < (int) array_elements(bind); i++) + { + bind[i].length= &length[i]; + bind[i].is_null= &is_null[i]; + is_null[i]= 0; + } + + rc= mysql_stmt_bind_param(stmt, 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]= my_sprintf(str_data, (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, 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= my_sprintf(data, (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(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 bind[3]; + ulong length[3]; + + 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*) bind, sizeof(bind)); + + /* tinyint */ + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[0].buffer= (void *)&tiny_data; + + /* string->float */ + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (void *)&real_data; + bind[1].buffer_length= sizeof(real_data); + bind[1].length= &length[1]; + length[1]= 10; + + /* double */ + bind[2].buffer_type= MYSQL_TYPE_DOUBLE; + bind[2].buffer= (void *)&double_data; + + tiny_data= 1; + strmov(real_data, "10.2"); + double_data= 34.5; + rc= mysql_stmt_bind_param(stmt, 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 bind[2]; + my_bool is_null[2]; + + 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].is_null= &is_null[0]; + is_null[0]= 1; + bind[1]= bind[0]; + + rc= mysql_stmt_bind_param(stmt, 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 */ + bind[0].buffer_type= MYSQL_TYPE_NULL; + is_null[0]= 0; /* reset */ + bind[1]= bind[0]; + + rc= mysql_stmt_bind_param(stmt, 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 */ + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&nData; /* this buffer won't be altered */ + bind[0].length= 0; + bind[1]= bind[0]; + bind[0].is_null= &is_null[0]; + 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, 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++) + { + 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 bind[11]; + ulong length[11]; + my_bool is_null[11]; + + 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(bind, sizeof(bind)); + for (i= 0; i < (int) array_elements(bind); i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].is_null= &is_null[i]; + bind[i].length= &length[i]; + } + 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, 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 bind[2]; + ulong length[2]; + + 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*) bind, sizeof(bind)); + + /* string data */ + nData= 10; + strmov(szData, (char *)"venu"); + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (void *)szData; + bind[1].buffer_length= 4; + bind[1].length= &length[1]; + length[1]= 4; + + bind[0].buffer= (void *)&nData; + bind[0].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, 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 bind[2]; + int32 int_data; + char str_data[32]; + unsigned long str_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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&int_data; + + bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[1].buffer= (void *)str_data; + bind[1].buffer_length= array_elements(str_data); + bind[1].length= &str_length; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + int_data= 1; + strcpy(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); +} + + +/* Test BUG#1115 (incorrect string parameter value allocation) */ + +static void test_bug1115() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_BIND bind[1]; + ulong length[1]; + char szData[11]; + + 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), " + "(\"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*) bind, sizeof(bind)); + + strmov(szData, (char *)"abc"); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 3; + + rc= mysql_stmt_bind_param(stmt, 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"); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 4; + bind[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, 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"); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 3; + bind[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, 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 bind[1]; + ulong length[1]; + char szData[11]; + + 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*) bind, sizeof(bind)); + + strmov(szData, (char *)"abc"); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 3; + bind[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, 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"); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 4; + bind[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, 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"); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 3; + bind[0].is_null= 0; + + rc= mysql_stmt_bind_param(stmt, 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 bind[4]; + int num; + my_bool isnull; + int rc, i; + + 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*) bind, sizeof(bind)); + + num= 22; + isnull= 0; + for (i= 0 ; i < 4 ; i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].buffer= (void *)# + bind[i].is_null= &isnull; + } + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + isnull= 1; + for (i= 0 ; i < 4 ; i++) + bind[i].is_null= &isnull; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + isnull= 0; + num= 88; + for (i= 0 ; i < 4 ; i++) + bind[i].is_null= &isnull; + + 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 * 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; + + 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 bind[2]; + ulong length[2]; + + 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*) bind, sizeof(bind)); + + nData= 1; + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= szData; /* string data */ + bind[0].buffer_length= sizeof(szData); + bind[0].length= &length[0]; + length[0]= my_sprintf(szData, (szData, "updated-data")); + + bind[1].buffer= (void *) &nData; + bind[1].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, 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 bind[3]; + + 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*) bind, sizeof(bind)); + + bind[0].buffer= (void *)&int_data; + bind[0].buffer_type= MYSQL_TYPE_LONG; + + bind[1].buffer_type= MYSQL_TYPE_STRING; + + bind[2]= bind[1]; + rc= mysql_stmt_bind_param(stmt, 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 bind[2]; + my_bool is_null[2]; + + 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*) bind, sizeof(bind)); + + bind[0].buffer= (void *)&length; + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].is_null= &is_null[0]; + is_null[0]= 0; + length= 0; + + bind[1].buffer= data; /* string data */ + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].length= &length1; + bind[1].is_null= &is_null[1]; + is_null[1]= 0; + rc= mysql_stmt_bind_param(stmt, 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); + + my_sprintf(data, (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, length1; + my_bool true_value; + MYSQL_RES *result; + MYSQL_BIND bind[2]; + MYSQL_FIELD *field; + + 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*) bind, sizeof(bind)); + + bind[0].buffer= data; /* string data */ + bind[0].buffer_length= sizeof(data); + bind[0].length= &length1; + bind[0].buffer_type= MYSQL_TYPE_STRING; + length1= 0; + + bind[1]= bind[0]; + bind[1].buffer_type= MYSQL_TYPE_BLOB; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + length= my_sprintf(data, (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); + + my_sprintf(data, (data, "%ld", (long)i*length)); + verify_col_data("test_long_data_str", "length(longstr)", data); + + my_sprintf(data, (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*) bind, sizeof(*bind)); + bind[0].buffer_type= MYSQL_TYPE_BLOB; + bind[0].buffer= (void *) &data; /* this buffer won't be altered */ + bind[0].buffer_length= 16; + bind[0].length= &blob_length; + bind[0].error= &bind[0].error_value; + rc= mysql_stmt_bind_result(stmt, bind); + data[16]= 0; + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED); + DIE_UNLESS(bind[0].error_value); + DIE_UNLESS(strlen(data) == 16); + DIE_UNLESS(blob_length == max_blob_length); + + /* Fetch all data */ + bzero((char*) (bind+1), sizeof(*bind)); + bind[1].buffer_type= MYSQL_TYPE_BLOB; + bind[1].buffer= (void *) &data; /* this buffer won't be altered */ + bind[1].buffer_length= sizeof(data); + bind[1].length= &blob_length; + bzero(data, sizeof(data)); + mysql_stmt_fetch_column(stmt, 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 bind[2]; + + + 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*) bind, sizeof(bind)); + + bind[0].buffer= (void *)&length; + bind[0].buffer_type= MYSQL_TYPE_LONG; + length= 0; + + bind[1].buffer= data; /* string data */ + bind[1].buffer_type= MYSQL_TYPE_LONG_BLOB; + rc= mysql_stmt_bind_param(stmt, 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 bind[2]; + ulong length[2]; + + 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*) bind, sizeof(bind)); + + nData= 1; + strmov(szData, "MySQL"); + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= szData; /* string data */ + bind[1].buffer_length= sizeof(szData); + bind[1].length= &length[1]; + length[1]= 5; + + bind[0].buffer= (void *)&nData; + bind[0].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, 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 bind[2]; + ulong length[2]; + + 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*) bind, sizeof(bind)); + + /* string data */ + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= szData; + bind[0].buffer_length= sizeof(szData); + bind[0].length= &length[0]; + length[0]= my_sprintf(szData, (szData, "inserted-data")); + + bind[1].buffer= (void *)&nData; + bind[1].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= szData; + bind[0].buffer_length= sizeof(szData); + bind[0].length= &length[0]; + length[0]= my_sprintf(szData, (szData, "updated-data")); + + bind[1].buffer= (void *)&nData; + bind[1].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, 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; + + 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 length, length1; + char szData[100]; + MYSQL_BIND 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *) &nData; /* integer data */ + bind[0].is_null= &is_null[0]; + + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= szData; /* string data */ + bind[1].buffer_length= sizeof(szData); + bind[1].length= &length1; + 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, 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); + + 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 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 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(bind, sizeof(bind)); + for (i= 0; i < (int) array_elements(bind); i++) + { + bind[i].length= &length[i]; + bind[i].is_null= &is_null[i]; + } + + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[0].buffer= (void *)&t_data; + + bind[1].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer_type= MYSQL_TYPE_LONG; + + bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + bind[1].buffer= (void *)&s_data; + + bind[2].buffer= (void *)&i_data; + bind[3].buffer= (void *)&b_data; + + bind[4].buffer_type= MYSQL_TYPE_FLOAT; + bind[4].buffer= (void *)&f_data; + + bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + bind[5].buffer= (void *)&d_data; + + bind[6].buffer_type= MYSQL_TYPE_STRING; + bind[6].buffer= (void *)szData; + bind[6].buffer_length= sizeof(szData); + bind[6].length= &szLength; + + bind[7].buffer_type= MYSQL_TYPE_TINY_BLOB; + bind[7].buffer= (void *)&bData; + bind[7].length= &bLength; + 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, 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 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *) t_data; + bind[0].buffer_length= sizeof(t_data); + bind[0].error= &bind[0].error_value; + + bind[1].buffer_type= MYSQL_TYPE_FLOAT; + bind[1].buffer= (void *)&s_data; + bind[1].buffer_length= 0; + bind[1].error= &bind[1].error_value; + + bind[2].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer= (void *)&i_data; + bind[2].buffer_length= 0; + bind[2].error= &bind[2].error_value; + + bind[3].buffer_type= MYSQL_TYPE_TINY; + bind[3].buffer= (void *)&b_data; + bind[3].buffer_length= 0; + bind[3].error= &bind[3].error_value; + + bind[4].buffer_type= MYSQL_TYPE_LONG; + bind[4].buffer= (void *)&f_data; + bind[4].buffer_length= 0; + bind[4].error= &bind[4].error_value; + + bind[5].buffer_type= MYSQL_TYPE_STRING; + bind[5].buffer= (void *)d_data; + bind[5].buffer_length= sizeof(d_data); + bind[5].error= &bind[5].error_value; + + bind[6].buffer_type= MYSQL_TYPE_LONG; + bind[6].buffer= (void *)&bData; + bind[6].buffer_length= 0; + bind[6].error= &bind[6].error_value; + + bind[7].buffer_type= MYSQL_TYPE_DOUBLE; + bind[7].buffer= (void *)&szData; + bind[7].buffer_length= 0; + bind[7].error= &bind[7].error_value; + + for (i= 0; i < array_elements(bind); i++) + { + bind[i].is_null= &is_null[i]; + bind[i].length= &length[i]; + } + + stmt= mysql_simple_prepare(mysql, "select * from test_bind_result"); + check_stmt(stmt); + + rc= mysql_stmt_bind_result(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED); + DIE_UNLESS(bind[4].error_value == 1); + + 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 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*) bind, sizeof(bind)); + + for (i= 0; i < (int) array_elements(bind); i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].buffer= (void *) &data[i]; + } + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + while (count--) + { + rc= 10+count; + for (i= 0; i < (int) array_elements(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(bind); i++) + { + bind[i].buffer= (void *) &data[i]; + bind[i].length= &length[i]; + bind[i].is_null= &is_null[i]; + } + + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[0].buffer= (void *)&i8_data; + + bind[1].buffer_type= MYSQL_TYPE_SHORT; + bind[1].buffer= (void *)&i16_data; + + bind[2].buffer_type= MYSQL_TYPE_LONG; + bind[2].buffer= (void *)&i32_data; + + bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + bind[3].buffer= (void *)&i64_data; + + bind[4].buffer_type= MYSQL_TYPE_FLOAT; + bind[4].buffer= (void *)&f_data; + + bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + bind[5].buffer= (void *)&d_data; + + bind[6].buffer_type= MYSQL_TYPE_STRING; + bind[6].buffer= (void *)&s_data; + bind[6].buffer_length= sizeof(s_data); + + 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 (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= my_sprintf(buff, (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], 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 bind[8]; + my_bool is_null[8]; + ulong length[8]; + + myheader("test_fetch_date"); + + 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(14), \ + c4 year, \ + c5 datetime, \ + c6 timestamp(4), \ + c7 timestamp(6))"); + myquery(rc); + + 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(bind, sizeof(bind)); + for (i= 0; i < array_elements(bind); i++) + { + bind[i].is_null= &is_null[i]; + bind[i].length= &length[i]; + } + + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[1]= bind[2]= bind[0]; + + bind[0].buffer= (void *)&date; + bind[0].buffer_length= sizeof(date); + bind[0].length= &d_length; + + bind[1].buffer= (void *)&time; + bind[1].buffer_length= sizeof(time); + bind[1].length= &t_length; + + bind[2].buffer= (void *)&ts; + bind[2].buffer_length= sizeof(ts); + bind[2].length= &ts_length; + + bind[3].buffer_type= MYSQL_TYPE_LONG; + bind[3].buffer= (void *)&year; + bind[3].length= &y_length; + + bind[4].buffer_type= MYSQL_TYPE_STRING; + bind[4].buffer= (void *)&dt; + bind[4].buffer_length= sizeof(dt); + bind[4].length= &dt_length; + + bind[5].buffer_type= MYSQL_TYPE_STRING; + bind[5].buffer= (void *)&ts_4; + bind[5].buffer_length= sizeof(ts_4); + bind[5].length= &ts4_length; + + bind[6].buffer_type= MYSQL_TYPE_STRING; + bind[6].buffer= (void *)&ts_6; + bind[6].buffer_length= sizeof(ts_6); + 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, 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)", 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(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 bind[6]; + 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(14), \ + 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*) bind, sizeof(bind)); + + /*tinyint*/ + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[0].buffer= (void *)&tData; + + /*smallint*/ + bind[1].buffer_type= MYSQL_TYPE_SHORT; + bind[1].buffer= (void *)&sData; + + /*mediumint*/ + bind[2].buffer_type= MYSQL_TYPE_LONG; + bind[2].buffer= (void *)&nData; + + /*int*/ + bind[3].buffer_type= MYSQL_TYPE_LONG; + bind[3].buffer= (void *)&nData; + + /*integer*/ + bind[4].buffer_type= MYSQL_TYPE_LONG; + bind[4].buffer= (void *)&nData; + + /*bigint*/ + bind[5].buffer_type= MYSQL_TYPE_LONGLONG; + bind[5].buffer= (void *)&bData; + + rc= mysql_stmt_bind_param(stmt, 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 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*) bind, sizeof(bind)); + + /* tinyint */ + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[0].buffer= (void *)&tiny_data; + + /* string */ + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= str_data; + bind[1].buffer_length= sizeof(str_data);; + bind[1].length= &length; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + /* now, execute the prepared statement to insert 10 records.. */ + for (tiny_data= 0; tiny_data < 3; tiny_data++) + { + length= my_sprintf(str_data, (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 bind[1]; + MYSQL_RES *result; + unsigned int count; + int rc; + + myheader("test_stmt_close"); + + if (!opt_silent) + fprintf(stdout, "\n Establishing a test connection ..."); + if (!(lmysql= mysql_init(NULL))) + { + myerror("mysql_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); + } + lmysql->reconnect= 1; + if (!opt_silent) + fprintf(stdout, " OK"); + + + /* set AUTOCOMMIT to ON*/ + mysql_autocommit(lmysql, TRUE); + + 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 hande 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*) bind, sizeof(bind)); + + bind[0].buffer= (void *)&count; + bind[0].buffer_type= MYSQL_TYPE_LONG; + count= 100; + + rc= mysql_stmt_bind_param(stmt_x, 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); +} + +#if NOT_USED + +/* Insert meta info .. */ + +static void test_insert_meta() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_RES *result; + MYSQL_FIELD *field; + + myheader("test_insert_meta"); + + 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), col3 varchar(30))"); + myquery(rc); + + strmov(query, "INSERT INTO test_prep_insert VALUES(10, 'venu1', 'test')"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 0); + + result= mysql_param_result(stmt); + mytest_r(result); + + mysql_stmt_close(stmt); + + strmov(query, "INSERT INTO test_prep_insert VALUES(?, 'venu', ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + result= mysql_param_result(stmt); + mytest(result); + + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + field= mysql_fetch_field(result); + mytest(field); + if (!opt_silent) + fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", field->name, "col1"); + DIE_UNLESS(strcmp(field->name, "col1") == 0); + + field= mysql_fetch_field(result); + mytest(field); + if (!opt_silent) + fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", field->name, "col3"); + DIE_UNLESS(strcmp(field->name, "col3") == 0); + + field= mysql_fetch_field(result); + mytest_r(field); + + mysql_free_result(result); + mysql_stmt_close(stmt); +} + + +/* Update meta info .. */ + +static void test_update_meta() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_RES *result; + MYSQL_FIELD *field; + + myheader("test_update_meta"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_update"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_prep_update(col1 tinyint, \ + col2 varchar(50), col3 varchar(30))"); + myquery(rc); + + strmov(query, "UPDATE test_prep_update SET col1=10, col2='venu1' WHERE col3='test'"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 0); + + result= mysql_param_result(stmt); + mytest_r(result); + + mysql_stmt_close(stmt); + + strmov(query, "UPDATE test_prep_update SET col1=?, col2='venu' WHERE col3=?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + result= mysql_param_result(stmt); + mytest(result); + + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + field= mysql_fetch_field(result); + mytest(field); + if (!opt_silent) + { + fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col1"); + fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_update"); + } + DIE_UNLESS(strcmp(field->name, "col1") == 0); + DIE_UNLESS(strcmp(field->table, "test_prep_update") == 0); + + field= mysql_fetch_field(result); + mytest(field); + if (!opt_silent) + { + fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col3"); + fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_update"); + } + DIE_UNLESS(strcmp(field->name, "col3") == 0); + DIE_UNLESS(strcmp(field->table, "test_prep_update") == 0); + + field= mysql_fetch_field(result); + mytest_r(field); + + mysql_free_result(result); + mysql_stmt_close(stmt); +} + + +/* Select meta info .. */ + +static void test_select_meta() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_RES *result; + MYSQL_FIELD *field; + + myheader("test_select_meta"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_select"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE test_prep_select(col1 tinyint, \ + col2 varchar(50), col3 varchar(30))"); + myquery(rc); + + strmov(query, "SELECT * FROM test_prep_select WHERE col1=10"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 0); + + result= mysql_param_result(stmt); + mytest_r(result); + + strmov(query, "SELECT col1, col3 from test_prep_select WHERE col1=? AND col3='test' AND col2= ?"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + verify_param_count(stmt, 2); + + result= mysql_param_result(stmt); + mytest(result); + + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + field= mysql_fetch_field(result); + mytest(field); + if (!opt_silent) + { + fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col1"); + fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_select"); + } + DIE_UNLESS(strcmp(field->name, "col1") == 0); + DIE_UNLESS(strcmp(field->table, "test_prep_select") == 0); + + field= mysql_fetch_field(result); + mytest(field); + if (!opt_silent) + { + fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col2"); + fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_select"); + } + DIE_UNLESS(strcmp(field->name, "col2") == 0); + DIE_UNLESS(strcmp(field->table, "test_prep_select") == 0); + + field= mysql_fetch_field(result); + mytest_r(field); + + mysql_free_result(result); + mysql_stmt_close(stmt); +} +#endif + + +/* 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 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&id; + bind[0].is_null= &is_null[0]; + bind[0].length= &length[0]; + is_null[0]= 0; + length[0]= 0; + + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (void *)name; + bind[1].buffer_length= sizeof(name); + bind[1].length= &length[1]; + bind[1].is_null= &is_null[1]; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, 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, 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; + int int_data; + int rc; + char str_data[50]; + ulonglong affected_rows; + MYSQL_BIND bind[3]; + my_bool is_null; + + 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(14))")) + { + 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*) bind, sizeof(bind)); + + /* INTEGER PART */ + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&int_data; + + /* STRING PART */ + bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[1].buffer= (void *)str_data; + bind[1].buffer_length= sizeof(str_data); + + /* SMALLINT PART */ + bind[2].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer= (void *)&small_data; + bind[2].is_null= &is_null; + is_null= 0; + + /* Bind the buffers */ + if (mysql_stmt_bind_param(stmt, 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; + long length; + MYSQL_BIND 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*) bind, sizeof(bind)); + + is_null= 0; + bind[0].buffer_type= MYSQL_TYPE_SHORT; + bind[0].buffer= (void *)&id; + bind[0].is_null= &is_null; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + id= 30; + length= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + if (thread_query((char *)"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_init(NULL))) + { + fprintf(stdout, "\n mysql_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_local->reconnect= 1; + + 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); + + 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; + myheader("test_prepare_multi_statements"); + + if (!(mysql_local= mysql_init(NULL))) + { + fprintf(stderr, "\n mysql_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_local->reconnect= 1; + 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 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *) &nData; /* integer data */ + bind[0].length= &length; + bind[0].is_null= &is_null[0]; + + length= 0; + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= szData; /* string data */ + bind[1].buffer_length= sizeof(szData); + bind[1].length= &length1; + 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, 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 bind[1]; + + 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *) &nData; /* integer data */ + bind[0].length= &length; + 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, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, 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 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *) &id; + bind[0].length= 0; + 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, 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, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, 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 bind[4]; + my_bool is_null[4]= {0}; + MYSQL_TIME tm[4]; + ulong second_part; + uint year, month, day, hour, minute, sec; + + 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_TIMESTAMP; + bind[1].buffer_type= MYSQL_TYPE_TIME; + bind[2].buffer_type= MYSQL_TYPE_DATETIME; + bind[3].buffer_type= MYSQL_TYPE_DATE; + + for (i= 0; i < (int) array_elements(bind); i++) + { + bind[i].buffer= (void *) &tm[i]; + bind[i].is_null= &is_null[i]; + bind[i].length= &length[i]; + 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, bind); + check_execute(stmt, rc); + + for (count= 0; count < row_count; count++) + { + for (i= 0; i < (int) array_elements(bind); i++) + { + tm[i].neg= 0; + tm[i].second_part= second_part+count; + if (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 (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, 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(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); + DIE_UNLESS(tm[i].month == 0 || tm[i].month == month+count); + DIE_UNLESS(tm[i].day == 0 || tm[i].day == day+count); + + 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(14), \ + 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(10), \ + c2 TIMESTAMP(14), \ + c3 TIMESTAMP, \ + c4 TIMESTAMP(6))"); + + 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); +} + + +/* Misc tests to keep pure coverage happy */ + +static void test_pure_coverage() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + 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*) bind, sizeof(bind)); + + bind[0].length= &length; + bind[0].is_null= 0; + bind[0].buffer_length= 0; + + bind[0].buffer_type= MYSQL_TYPE_GEOMETRY; + rc= mysql_stmt_bind_param(stmt, bind); + check_execute_r(stmt, rc); /* unsupported buffer type */ + + bind[0].buffer_type= MYSQL_TYPE_STRING; + rc= mysql_stmt_bind_param(stmt, 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); + + bind[0].buffer_type= MYSQL_TYPE_GEOMETRY; + rc= mysql_stmt_bind_result(stmt, bind); + check_execute_r(stmt, rc); /* unsupported buffer type */ + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute_r(stmt, rc); /* commands out of sync */ + + 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 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(bind, sizeof(bind)); + bind[0].length= &length; + bind[0].is_null= &is_null; + bind[0].buffer_length= 1; + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)buffer; + bind[0].error= &bind[0].error_value; + + rc= mysql_stmt_bind_result(stmt, 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(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); + + bind[0].buffer_length= 8; + rc= mysql_stmt_bind_result(stmt, 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); + + bind[0].buffer_length= 12; + rc= mysql_stmt_bind_result(stmt, 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); + + bind[0].buffer_length= 6; + rc= mysql_stmt_bind_result(stmt, bind);/* re-bind */ + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED); + DIE_UNLESS(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 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(bind, sizeof(MYSQL_BIND)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)str[0]; + bind[0].buffer_length= sizeof(str[0]); + bind[1]= bind[2]= bind[3]= bind[0]; + bind[1].buffer= (void *)str[1]; + bind[2].buffer= (void *)str[2]; + bind[3].buffer= (void *)str[3]; + + rc= mysql_stmt_bind_result(stmt, 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 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_SHORT; + bind[0].buffer= (void *)&short_value; + bind[0].is_unsigned= TRUE; + bind[0].length= &s_length; + + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= (void *)&long_value; + bind[1].length= &l_length; + + bind[2].buffer_type= MYSQL_TYPE_LONGLONG; + bind[2].buffer= (void *)&longlong_value; + bind[2].length= &ll_length; + + bind[3].buffer_type= MYSQL_TYPE_TINY; + bind[3].buffer= (void *)&tiny_value; + bind[3].is_unsigned= TRUE; + bind[3].length= &t_length; + + rc= mysql_stmt_bind_result(stmt, 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 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_SHORT; + bind[0].buffer= (void *)&short_value; + bind[0].length= &s_length; + + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= (void *)&long_value; + bind[1].length= &l_length; + + bind[2].buffer_type= MYSQL_TYPE_LONGLONG; + bind[2].buffer= (void *)&longlong_value; + bind[2].length= &ll_length; + + bind[3].buffer_type= MYSQL_TYPE_TINY; + bind[3].buffer= (void *)&tiny_value; + bind[3].is_unsigned= TRUE; + bind[3].length= &t_length; + + rc= mysql_stmt_bind_result(stmt, 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 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_SHORT; + bind[0].buffer= (void *)&short_value; + bind[0].length= &s_length; + + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= (void *)&long_value; + bind[1].length= &l_length; + + bind[2].buffer_type= MYSQL_TYPE_LONGLONG; + bind[2].buffer= (void *)&longlong_value; + bind[2].length= &ll_length; + + bind[3].buffer_type= MYSQL_TYPE_TINY; + bind[3].buffer= (void *)&tiny_value; + bind[3].length= &t_length; + + rc= mysql_stmt_bind_result(stmt, 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; + MYSQL_BIND bind[1]; + char table_type[NAME_LEN]; + ulong type_length; + 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 @@table_type"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= table_type; + bind[0].length= &type_length; + bind[0].buffer_length= NAME_LEN; + + rc= mysql_stmt_bind_result(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n default table type: %s(%ld)", table_type, type_length); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + + stmt= mysql_simple_prepare(mysql, "SELECT @@table_type"); + check_stmt(stmt); + + result= mysql_stmt_result_metadata(stmt); + mytest(result); + DIE_UNLESS(mysql_stmt_field_count(stmt) == mysql_num_fields(result)); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(1 == my_process_stmt_result(stmt)); + + verify_prepare_field(result, 0, + "@@table_type", "", /* field and its org name */ + mysql_get_server_version(mysql) <= 50000 ? + MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, + "", "", /* table and its org name */ + "", type_length, 0); /* db name, length */ + + 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 */ + "", 10, 0); /* db name, length */ + + 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 */ + "", 10, 0); /* db name, length */ + + 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 OPTION 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 OPTION 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); +} + + +/* + Test a misc GRANT option + bug #89 (reported by mark@mysql.com) +*/ + +static void test_prepare_grant() +{ + int rc; + + 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_init(NULL))) + { + myerror("mysql_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); + } + lmysql->reconnect= 1; + 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)); + + } +} + + +/* + 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 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= data_dir; + bind[0].buffer_length= FN_REFLEN; + bind[1]= bind[0]; + + rc= mysql_stmt_bind_result(stmt, 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 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)data; + bind[0].buffer_length= 25; + bind[0].is_null= &is_null; + + is_null= 0; + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + strcpy(data, "8.0"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + data[0]= 0; + rc= mysql_stmt_bind_result(stmt, 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); + + strcpy(data, "5.61"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + data[0]= 0; + rc= mysql_stmt_bind_result(stmt, 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); + + strcpy(data, "10.22"); is_null= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + data[0]= 0; + rc= mysql_stmt_bind_result(stmt, 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, "", 64, 0); + + verify_prepare_field(result, 1, "Type", "COLUMN_TYPE", + MYSQL_TYPE_BLOB, 0, 0, "", 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, "", 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, "", 3, 0); + + verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT", + mysql_get_server_version(mysql) <= 50000 ? + MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, + 0, 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, "", 20, 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_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_LEN*MAX_KEY, 0); + + verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING, + "", "", "", NAME_LEN, 0); + + verify_prepare_field(result, 6, "key_len", "", + (mysql_get_server_version(mysql) <= 50000 ? + MYSQL_TYPE_LONGLONG : MYSQL_TYPE_VAR_STRING), + "", "", "", + (mysql_get_server_version(mysql) <= 50000 ? 3 : 4096), + 0); + + verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING, + "", "", "", NAME_LEN*16, 0); + + verify_prepare_field(result, 8, "rows", "", MYSQL_TYPE_LONGLONG, + "", "", "", 10, 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_init(NULL))) + { + myerror("mysql_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); + } + lmysql->reconnect= 1; + 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 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_SHORT; + bind[0].buffer= (void *)&id; + + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (void *)&data; + bind[1].buffer_length= 255; + bind[1].length= &length; + + id= 9876; + length= (ulong)(strmov((char *)data, "MySQL - Open Source Database")- data); + + rc= mysql_stmt_bind_param(stmt, 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, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bind[1].buffer_length= 255; + rc= mysql_stmt_bind_result(stmt, 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 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*) bind, sizeof(bind)); + + bind[0].buffer= (void *)&i; + 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, 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, 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 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(14))"); + 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&c1; + + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (void *)c2; + bind[1].buffer_length= sizeof(c2); + + bind[2]= bind[1]; + bind[2].buffer= (void *)c3; + bind[2].buffer_length= sizeof(c3); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, 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 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)data; + bind[0].buffer_length= 11; + bind[0].is_null= &is_null; + bind[0].length= &length; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch_column(stmt, bind, 0, 0); + check_execute_r(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, 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, 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, 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, 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, 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, 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 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&bc1; + bind[0].buffer_length= 0; + bind[0].is_null= 0; + bind[0].length= &bl1; + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (void *)bc2; + bind[1].buffer_length= 7; + bind[1].is_null= 0; + bind[1].length= &bl2; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch_column(stmt, 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; + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)c2; + bind[0].buffer_length= 7; + bind[0].is_null= 0; + bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, 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, 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; + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&c1; + bind[0].buffer_length= 0; + bind[0].is_null= 0; + bind[0].length= &l1; + + rc= mysql_stmt_fetch_column(stmt, 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; + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)c2; + bind[0].buffer_length= 7; + bind[0].is_null= 0; + bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, 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, 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; + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&c1; + bind[0].buffer_length= 0; + bind[0].is_null= 0; + bind[0].length= &l1; + + rc= mysql_stmt_fetch_column(stmt, 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, 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 a memory ovverun bug */ + +static void test_mem_overun() +{ + char buffer[10000], field[10]; + MYSQL_STMT *stmt; + MYSQL_RES *field_res; + int rc, i, length; + + 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%d 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 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&bc1; + bind[0].length= &bl1; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + c2[0]= '\0'; l2= 0; + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)c2; + bind[0].buffer_length= 7; + bind[0].is_null= 0; + bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, 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; + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&c1; + bind[0].buffer_length= 0; + bind[0].is_null= 0; + bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, 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 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&bc1; + bind[0].buffer_length= 0; + bind[0].is_null= 0; + bind[0].length= &bl1; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_bind_result(stmt, 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; + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)c2; + bind[0].buffer_length= 7; + bind[0].is_null= 0; + bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, 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; + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&c1; + bind[0].buffer_length= 0; + bind[0].is_null= 0; + bind[0].length= &l2; + + rc= mysql_stmt_fetch_column(stmt, 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 bind[2]; + char c1[5], c2[5]; + int rc; + + 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 */ + strcpy(query, "SET SQL_MODE= \"PIPES_AS_CONCAT\""); + if (!opt_silent) + fprintf(stdout, "\n With %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + strcpy(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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)c1; + bind[0].buffer_length= 2; + + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (void *)c2; + bind[1].buffer_length= 3; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + strcpy(c1, "My"); strcpy(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); + + strcpy(query, "SELECT connection_id ()"); + if (!opt_silent) + fprintf(stdout, "\n query: %s", query); + stmt= mysql_simple_prepare(mysql, query); + check_stmt_r(stmt); + + /* ANSI */ + strcpy(query, "SET SQL_MODE= \"ANSI\""); + if (!opt_silent) + fprintf(stdout, "\n With %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + strcpy(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, bind); + check_execute(stmt, rc); + + strcpy(c1, "My"); strcpy(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 ... */ + strcpy(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 */ + strcpy(query, "SET SQL_MODE= \"IGNORE_SPACE\""); + if (!opt_silent) + fprintf(stdout, "\n With %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + strcpy(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 bind[6]; + MYSQL_TIME ts; + MYSQL_RES *prep_res; + char strts[30]; + ulong length; + int rc, field_count; + char name; + + 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_TIMESTAMP; + bind[0].buffer= (void *)&ts; + bind[0].buffer_length= sizeof(ts); + + bind[2]= bind[1]= bind[0]; + + bind[3].buffer_type= MYSQL_TYPE_STRING; + bind[3].buffer= (void *)strts; + bind[3].buffer_length= sizeof(strts); + bind[3].length= &length; + + bind[5]= bind[4]= bind[3]; + + rc= mysql_stmt_bind_param(stmt, 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, "SELECT a, b, c FROM test_ts WHERE %c=?", name); + + if (!opt_silent) + fprintf(stdout, "\n %s", query); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_bind_param(stmt, 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 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*) bind, sizeof(bind)); + + bind[0].buffer= (void *)int_data; + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[2]= bind[1]= bind[0]; + bind[1].buffer= (void *)(int_data + 1); + bind[2].buffer= (void *)(int_data + 2); + + rc= mysql_stmt_bind_param(stmt, 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))"); + 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"; + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *) data; + bind[0].buffer_length= strlen(data); + bind[0].is_null= 0; + bind[0].length= 0; + + rc= mysql_stmt_bind_param(stmt, 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"; + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *) data; + bind[0].buffer_length= strlen(data); + + rc= mysql_stmt_bind_param(stmt, 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, "SHOW DATABASES", 100); + 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, "SHOW DATABASES", 100); + 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 == MYSQL_NO_DATA); + + /* 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 == MYSQL_NO_DATA); + + 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 where a+1=(SELECT 1+ccc from t1 where ccc+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, "droped %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, "droped %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_manipulation"); + + 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 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)¶m; + 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, 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 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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&my_val; + bind[0].length= &my_length; + bind[0].is_null= (char*)&my_null; + + rc= mysql_stmt_bind_param(stmt_insert, 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 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)) \ +TYPE=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*) bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&my_val; + bind[0].length= &my_length; + bind[0].is_null= (char*)&my_null; + my_val= 1; + rc= mysql_stmt_bind_param(stmt, 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)) TYPE=InnoDB DEFAULT CHARSET=utf8"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 ( id int(8), name_id int(8), value varchar(10)) TYPE=InnoDB DEFAULT CHARSET=utf8"); + myquery(rc); + + rc= mysql_query(mysql, "create table t2 (id int(8), name_id int(8), value varchar(10)) TYPE=InnoDB DEFAULT CHARSET=utf8;"); + myquery(rc); + + rc= mysql_query(mysql, "create table t4(id int(8), value varchar(10)) TYPE=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], *bind= bind_array, *bind_end= 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; + 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= LL(9223372036854775807); + const longlong int64_min= -int64_max - 1; + + const ulonglong uint64_min= 0U; + const ulonglong uint64_max= ULL(18446744073709551615); + + 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(bind_array, sizeof(bind_array)); + + for (bind= bind_array; bind < bind_end; bind++) + bind->error= &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); + DIE_UNLESS(udouble_val == ulonglong2double(uint64_val)); + 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 (bind= bind_array; bind < bind_end; bind++) + printf("%d", (int) 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); + DIE_UNLESS(udouble_val == ulonglong2double(uint64_val)); + 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 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(&bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)str_data; + bind[0].buffer_length= strlen(str_data); + + bind[1].buffer= (void *)&int_data; + bind[1].buffer_type= MYSQL_TYPE_LONG; + + rc= mysql_stmt_bind_param(stmt, 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, 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 bind[2]; + char my_val[4]; + ulong my_length= 3L; + my_bool my_null= FALSE; + myheader("test_union_param"); + + strcpy(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*) bind, sizeof(bind)); + + /* bind parameters */ + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (char*) &my_val; + bind[0].buffer_length= 4; + bind[0].length= &my_length; + bind[0].is_null= (char*)&my_null; + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (char*) &my_val; + bind[1].buffer_length= 4; + bind[1].length= &my_length; + bind[1].is_null= (char*)&my_null; + + rc= mysql_stmt_bind_param(stmt, 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]; + + const char *koi8= "îÕ, ÚÁ ÒÙÂÁÌËÕ"; + const char *cp1251= "Íó, çà ðûáàëêó"; + 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(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 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(bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *) concat_arg0; + bind[0].buffer_length= strlen(concat_arg0); + + mysql_stmt_bind_param(stmt, bind); + + /* Execute the select statement */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bind[0].buffer= (void *) out_buff; + bind[0].buffer_length= OUT_BUFF_SIZE; + bind[0].length= &out_length; + + mysql_stmt_bind_result(stmt, bind); + + rc= mysql_stmt_fetch(stmt); + if (!opt_silent) + printf("Concat result: '%s'\n", out_buff); + check_execute(stmt, rc); + strcpy(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); + strcpy(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 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(bind, sizeof(bind)); + bzero(&time_in, sizeof(time_in)); + bzero(&time_out, sizeof(time_out)); + bzero(&datetime_in, sizeof(datetime_in)); + bzero(&datetime_out, sizeof(datetime_out)); + + bind[0].buffer_type= MYSQL_TYPE_TIME; + bind[0].buffer= (void *) &time_in; + bind[1].buffer_type= MYSQL_TYPE_DATETIME; + 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, bind); + + /* Execute the select statement */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bind[0].buffer= (void *) &time_out; + bind[1].buffer= (void *) &datetime_out; + + mysql_stmt_bind_result(stmt, 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 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(bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *) &res; + + mysql_stmt_bind_result(stmt, 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_bug4296"); + + 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 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(bind, sizeof(bind)); + bzero(&time_canonical, sizeof(time_canonical)); + bzero(&time_out, sizeof(time_out)); + bzero(&date_canonical, sizeof(date_canonical)); + bzero(&date_out, sizeof(date_out)); + bzero(&datetime_canonical, sizeof(datetime_canonical)); + bzero(&datetime_out, sizeof(datetime_out)); + + bind[0].buffer_type= MYSQL_TYPE_TIME; + bind[0].buffer= (void *) &time_out; + bind[1].buffer_type= MYSQL_TYPE_DATE; + bind[1].buffer= (void *) &date_out; + bind[2].buffer_type= MYSQL_TYPE_DATETIME; + 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, 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 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) character set latin1 collate latin1_bin NOT NULL default '', `DBINSTANCE` varchar(20) character set latin1 collate latin1_bin NOT NULL default '', PRIMARY KEY (`SERVERGRP`)) ENGINE=InnoDB DEFAULT CHARSET=latin1"); + myquery(rc); + rc= mysql_query(mysql,"CREATE TABLE `t2` ( `SERVERNAME` varchar(20) character set latin1 collate latin1_bin NOT NULL default '', `SERVERGRP` varchar(20) character set latin1 collate latin1_bin NOT NULL default '', PRIMARY KEY (`SERVERNAME`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;"); + myquery(rc); + rc= mysql_query(mysql,"CREATE TABLE `t3` ( `SERVERGRP` varchar(20) character set latin1 collate latin1_bin NOT NULL default '', `TABNAME` varchar(30) character set latin1 collate latin1_bin NOT NULL default '', `MAPSTATE` char(1) character set latin1 collate latin1_bin NOT NULL default '', `ACTSTATE` char(1) character set latin1 collate latin1_bin NOT NULL default '', `LOCAL_NAME` varchar(30) character set latin1 collate latin1_bin NOT NULL default '', `CHG_DATE` varchar(8) character set latin1 collate latin1_bin NOT NULL default '00000000', `CHG_TIME` varchar(6) character set latin1 collate latin1_bin NOT NULL default '000000', `MXUSER` varchar(12) character set latin1 collate latin1_bin NOT NULL default '', PRIMARY KEY (`SERVERGRP`,`TABNAME`,`MAPSTATE`,`ACTSTATE`,`LOCAL_NAME`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;"); + 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); + + strcpy(str_data, "TEST"); + bind[0].buffer_type= FIELD_TYPE_STRING; + bind[0].buffer= (char *)&str_data; + bind[0].buffer_length= 50; + bind[0].length= &length; + length= 4; + bind[0].is_null= (char*)&is_null; + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt,rc); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + assert(1 == my_process_stmt_result(stmt)); + } + 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); + assert(4 == my_process_stmt_result(stmt)); + } + 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 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) character set latin1 collate latin1_bin NOT NULL default '000', `RELID` char(2) character set latin1 collate latin1_bin NOT NULL default '', `REPORT` varchar(40) character set latin1 collate latin1_bin NOT NULL default '', `HANDLE` varchar(4) character set latin1 collate latin1_bin NOT NULL default '', `LOG_GROUP` varchar(4) character set latin1 collate latin1_bin NOT NULL default '', `USERNAME` varchar(12) character set latin1 collate latin1_bin NOT NULL default '', `VARIANT` varchar(12) character set latin1 collate latin1_bin NOT NULL default '', `TYPE` char(1) character set latin1 collate latin1_bin NOT NULL default '', `SRTF2` int(11) NOT NULL default '0', `VERSION` varchar(6) character set latin1 collate latin1_bin NOT NULL default '000000', `ERFDAT` varchar(8) character set latin1 collate latin1_bin NOT NULL default '00000000', `ERFTIME` varchar(6) character set latin1 collate latin1_bin NOT NULL default '000000', `ERFNAME` varchar(12) character set latin1 collate latin1_bin NOT NULL default '', `AEDAT` varchar(8) character set latin1 collate latin1_bin NOT NULL default '00000000', `AETIME` varchar(6) character set latin1 collate latin1_bin NOT NULL default '000000', `AENAME` varchar(12) character set latin1 collate latin1_bin NOT NULL default '', `DEPENDVARS` varchar(10) character set latin1 collate latin1_bin NOT NULL default '', `INACTIVE` char(1) character set latin1 collate latin1_bin NOT NULL default '', `CLUSTR` smallint(6) NOT NULL default '0', `CLUSTD` blob, PRIMARY KEY (`MANDT`,`RELID`,`REPORT`,`HANDLE`,`LOG_GROUP`,`USERNAME`,`VARIANT`,`TYPE`,`SRTF2`)) ENGINE=InnoDB DEFAULT CHARSET=latin1"); + 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); + for (i=0; i < 8; i++) { + strcpy(parms[i], "1"); + bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + bind[i].buffer = (char *)&parms[i]; + bind[i].buffer_length = 100; + bind[i].is_null = 0; + 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, bind); + check_execute(stmt,rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + assert(0 == my_process_stmt_result(stmt)); + + 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 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); + for (i= 0; i < 2; i++) { + sprintf((char *)&parms[i], "%d", i); + bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + bind[i].buffer = (char *)&parms[i]; + bind[i].buffer_length = 100; + bind[i].is_null = 0; + 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, bind); + check_execute(stmt,rc); + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + assert(0 == my_process_stmt_result(stmt)); + } + + 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 bind[1]; + long my_val = 0L; + 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); + + bind[0].buffer_type = FIELD_TYPE_LONG; + bind[0].buffer = (char *)&my_val; + bind[0].length = &my_length; + bind[0].is_null = (char*)&my_null; + rc= mysql_stmt_bind_param(insert_stmt, bind); + check_execute(insert_stmt, rc); + + for (i= 0; i < 3; i++) + { + 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); + assert(i + 1 == (int) my_process_stmt_result(select_stmt)); + } + 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); + assert(3 == my_process_stmt_result(stmt)); + } + 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 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) character set latin1 collate latin1_bin NOT NULL default '', K2C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '', K3C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '', K4N4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '0000', F1C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '', F2I4 int(11) NOT NULL default '0', F3N5 varchar(5) character set latin1 collate latin1_bin NOT NULL default '00000', F4I4 int(11) NOT NULL default '0', F5C8 varchar(8) character set latin1 collate latin1_bin NOT NULL default '', F6N4 varchar(4) character set latin1 collate latin1_bin 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)) ENGINE=InnoDB DEFAULT CHARSET=latin1"); + 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"); + + for (i= 0; i < 11; i++) + { + l[i]= 20; + bind[i].buffer_type= MYSQL_TYPE_STRING; + bind[i].is_null= 0; + bind[i].buffer= (char *)&parm[i]; + + strcpy(parm[i], "1"); + bind[i].buffer_length= 2; + 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, 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); + assert(1 == my_process_stmt_result(stmt)); + + 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 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(bind, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= &c1; + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= &c2; + + mysql_stmt_bind_result(stmt, 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 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(bind, sizeof(bind)); + bzero(tm, sizeof(tm)); + + bind[0].buffer_type= MYSQL_TYPE_DATE; + bind[0].buffer= &tm[0]; + bind[1].buffer_type= MYSQL_TYPE_DATE; + bind[1].buffer= &tm[1]; + + mysql_stmt_bind_param(stmt, 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 bind[1]; + char buff[600]; + int rc; + int32 no; + + myheader("test_bug5399"); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + 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, 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 *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); + + 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 (bind == 0 || query == 0 || param_str == 0) + { + fprintf(stderr, "Can't allocate enough memory for query structs\n"); + if (bind) + free(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(bind, MAX_PARAM_COUNT * sizeof(MYSQL_BIND)); + for (i= 0; i < MAX_PARAM_COUNT; ++i) + { + bind[i].buffer_type= MYSQL_TYPE_FLOAT; + 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, 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, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + + mysql_stmt_close(stmt); + free(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); + mysql_change_user(mysql, opt_user, opt_password, current_db); + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc != 0); + if (rc) + { + if (!opt_silent) + printf("Got error (as expected):\n%s", mysql_stmt_error(stmt)); + } + /* check that connection is OK */ + mysql_stmt_close(stmt); + 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 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(bind, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_STRING; + bind[0].buffer = &buffer; + bind[0].buffer_length = sizeof(buffer); + bind[0].length = &length; + + mysql_stmt_bind_result(stmt, 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 bind[1]; + MYSQL_RES *res; + MYSQL_ROW row; + const char *stmt_text; + char buffer[30]; + ulong length; + int rc; + + myheader("test_bug6058"); + + 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(bind, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_STRING; + bind[0].buffer = &buffer; + bind[0].buffer_length = sizeof(buffer); + bind[0].length = &length; + + mysql_stmt_bind_result(stmt, 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; + int rc; + + myheader("test_bug6059"); + + stmt_text= "SELECT 'foo' INTO OUTFILE 'x.3'"; + + stmt= mysql_stmt_init(mysql); + rc= 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 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(bind, sizeof(bind)); + bind[0].buffer= &b; + bind[0].buffer_type= MYSQL_TYPE_SHORT; + + mysql_stmt_bind_param(stmt, 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)); + 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)); +} + +/* + 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, current_db, + (ulong)strlen(current_db), 0); + myquery(rc); + rc= simple_command(mysql, COM_DROP_DB, current_db, + (ulong)strlen(current_db), 0); + myquery_r(rc); + rc= simple_command(mysql, COM_CREATE_DB, current_db, + (ulong)strlen(current_db), 0); + myquery(rc); + rc= simple_command(mysql, COM_CREATE_DB, 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 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); + + 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(bind, sizeof(bind)); + for (i= 0; i < stmt_field_count; ++i) + { + bind[i].buffer_type= MYSQL_TYPE_STRING; + bind[i].buffer_length= stmt_field_list[i].max_length + 1; + bind[i].buffer= malloc(bind[i].buffer_length); + } + mysql_stmt_bind_result(stmt, 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(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 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(bind, sizeof(bind)); + for (i= 0; i < 6; i++) + { + bind[i].buffer_type= MYSQL_TYPE_DATETIME; + bind[i].buffer= &tm[i]; + } + rc= mysql_stmt_bind_param(stmt, 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); + DIE_UNLESS(mysql_warning_count(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++) + bind[i].buffer_type= MYSQL_TYPE_DATE; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + DIE_UNLESS(mysql_warning_count(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++) + bind[i].buffer_type= MYSQL_TYPE_TIME; + + rc= mysql_stmt_bind_param(stmt, 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); + DIE_UNLESS(mysql_warning_count(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); +} + + +static void test_bug4172() +{ + MYSQL_STMT *stmt; + MYSQL_BIND 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(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= f; + bind[0].buffer_length= sizeof(f); + bind[0].length= &f_len; + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= d; + bind[1].buffer_length= sizeof(d); + bind[1].length= &d_len; + bind[2].buffer_type= MYSQL_TYPE_STRING; + bind[2].buffer= e; + bind[2].buffer_length= sizeof(e); + bind[2].length= &e_len; + + mysql_stmt_bind_result(stmt, 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 bind[1]; + char 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(bind, sizeof(bind)); + bind[0].buffer= buff; + bind[0].length= &length; + bind[0].buffer_type= MYSQL_TYPE_STRING; + + mysql_stmt_bind_param(stmt, 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); + + bind[0].buffer_length= sizeof(buff); + mysql_stmt_bind_result(stmt, bind); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + DIE_UNLESS(length == 1); + DIE_UNLESS((uchar) 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 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(&bind,sizeof(MYSQL_BIND)); + bind.buffer_type= MYSQL_TYPE_LONG; + bind.buffer= (void *)&Data; /* this buffer won't be altered */ + bind.length= &length; + 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, &bind); + DIE_UNLESS(rc == 0); + + /* retreive all result sets till we are at the end */ + while(!mysql_stmt_fetch(stmt)) + 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))) + 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, *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); + stmt_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, stmt_text, strlen(stmt_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(bind_array, sizeof(MYSQL_BIND) * bind_count); + for (bind= bind_array; bind < bind_array + bind_count; bind++) + bind->error= &bind->error_value; + bind= bind_array; + + bind->buffer= malloc(sizeof(uint8)); + bind->buffer_type= MYSQL_TYPE_TINY; + bind->is_unsigned= TRUE; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(uint32)); + bind->buffer_type= MYSQL_TYPE_LONG; + bind->is_unsigned= TRUE; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(int8)); + bind->buffer_type= MYSQL_TYPE_TINY; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(uint16)); + bind->buffer_type= MYSQL_TYPE_SHORT; + bind->is_unsigned= TRUE; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(int16)); + bind->buffer_type= MYSQL_TYPE_SHORT; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(uint16)); + bind->buffer_type= MYSQL_TYPE_SHORT; + bind->is_unsigned= TRUE; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(int8)); + bind->buffer_type= MYSQL_TYPE_TINY; + bind->is_unsigned= TRUE; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(float)); + bind->buffer_type= MYSQL_TYPE_FLOAT; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(float)); + bind->buffer_type= MYSQL_TYPE_FLOAT; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(double)); + bind->buffer_type= MYSQL_TYPE_DOUBLE; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(longlong)); + bind->buffer_type= MYSQL_TYPE_LONGLONG; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(ulonglong)); + bind->buffer_type= MYSQL_TYPE_LONGLONG; + bind->is_unsigned= TRUE; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(longlong)); + bind->buffer_type= MYSQL_TYPE_LONGLONG; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(longlong)); + bind->buffer_type= MYSQL_TYPE_LONGLONG; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(longlong)); + bind->buffer_type= MYSQL_TYPE_LONGLONG; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(longlong)); + bind->buffer_type= MYSQL_TYPE_LONGLONG; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(double)); + bind->buffer_type= MYSQL_TYPE_DOUBLE; + + DIE_UNLESS(++bind < bind_array + bind_count); + bind->buffer= malloc(sizeof(double)); + 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 ***************************/ + bind= bind_array; + + /* signed tiny -> tiny */ + DIE_UNLESS(*bind->error && * (int8*) bind->buffer == -10); + + /* signed tiny -> uint32 */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(*bind->error && * (int32*) bind->buffer == -10); + + /* unsigned tiny -> tiny */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(*bind->error && * (uint8*) bind->buffer == 200); + + /* short -> ushort */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(*bind->error && * (int16*) bind->buffer == -32767); + + /* ushort -> short */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(*bind->error && * (uint16*) bind->buffer == 64000); + + /* short -> ushort (no truncation, data is in the range of target type) */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(! *bind->error && * (uint16*) bind->buffer == 32000); + + /* ushort -> utiny */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(*bind->error && * (int8*) bind->buffer == 0); + + /* int -> float: no truncation, the number is a power of two */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(! *bind->error && * (float*) bind->buffer == 1073741824); + + /* int -> float: truncation, not enough bits in float */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(*bind->error); + + /* int -> double: no truncation */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(! *bind->error && * (double*) bind->buffer == 1073741825); + + /* double -> longlong: fractional part is lost */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(*bind->error && * (longlong*) bind->buffer == 123); + + /* double -> ulonglong, negative fp number to unsigned integer */ + DIE_UNLESS(++bind < bind_array + bind_count); + /* Value in the buffer is not defined: don't test it */ + DIE_UNLESS(*bind->error); + + /* double -> longlong, negative fp number to signed integer: no loss */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(! *bind->error && * (longlong*) bind->buffer == LL(-12345678910)); + + /* big numeric string -> number */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(*bind->error); + + /* junk string -> number */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(*bind->error && *(longlong*) bind->buffer == 0); + + /* string with trailing spaces -> number */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(! *bind->error && *(longlong*) bind->buffer == 12345); + + /* string with trailing spaces -> double */ + DIE_UNLESS(++bind < bind_array + bind_count); + DIE_UNLESS(! *bind->error && *(double*) bind->buffer == 12345.67); + + /* string with trailing junk -> double */ + DIE_UNLESS(++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*) 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 (bind= bind_array; bind < bind_array + bind_count; bind++) + free(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 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(&bind, sizeof(MYSQL_BIND)); + + bind.buffer= (void*) &buf; + bind.buffer_type= MYSQL_TYPE_TINY; + bind.is_unsigned= TRUE; + bind.error= &error; + + rc= mysql_stmt_bind_result(stmt, &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, &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); +} + + +/* + Read and parse arguments and MySQL options from my.cnf +*/ + +static const char *client_test_load_default_groups[]= { "client", 0 }; +static char **defaults_argv; + +static struct my_option client_test_long_options[] = +{ + {"count", 't', "Number of times test to be executed", (char **) &opt_count, + (char **) &opt_count, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, + {"database", 'D', "Database to use", (char **) &opt_db, (char **) &opt_db, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"debug", '#', "Output debug log", (gptr*) &default_dbug_option, + (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, + 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host", (char **) &opt_host, (char **) &opt_host, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"password", 'p', + "Password to use when connecting to server. If password is not given it's asked from the tty.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"port", 'P', "Port number to use for connection", (char **) &opt_port, + (char **) &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, + 0}, + {"socket", 'S', "Socket file to use for connection", + (char **) &opt_unix_socket, (char **) &opt_unix_socket, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"testcase", 'c', + "May disable some code when runs as mysql-test-run testcase.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DONT_ALLOW_USER_CHANGE + {"user", 'u', "User for login if not current user", (char **) &opt_user, + (char **) &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif + { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +static void usage(void) +{ + /* show the usage string when the user asks for this */ + putc('\n', stdout); + printf("%s Ver %s Distrib %s, for %s (%s)\n", + my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); + puts("By Monty, Venu, Kent and others\n"); + printf("\ +Copyright (C) 2002-2004 MySQL AB\n\ +This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ +and you are welcome to modify and redistribute it under the GPL license\n"); + printf("Usage: %s [OPTIONS] [TESTNAME1 TESTNAME2...]\n", my_progname); + my_print_help(client_test_long_options); + print_defaults("my", client_test_load_default_groups); + my_print_variables(client_test_long_options); +} + + +static struct my_tests_st my_tests[]= { + { "client_query", client_query }, + { "test_prepare_insert_update", test_prepare_insert_update}, +#if 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_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_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_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_truncation", test_truncation }, + { "test_truncation_option", test_truncation_option }, + { 0, 0 } +}; + + +static my_bool +get_one_option(int optid, const struct my_option *opt __attribute__((unused)), + char *argument) +{ + switch (optid) { + case '#': + DBUG_PUSH(argument ? argument : default_dbug_option); + break; + case 'c': + opt_testcase = 1; + break; + case 'p': + if (argument) + { + char *start=argument; + my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + opt_password= my_strdup(argument, MYF(MY_FAE)); + while (*argument) *argument++= 'x'; /* Destroy argument */ + if (*start) + start[1]=0; + } + else + tty_password= 1; + break; + case 's': + if (argument == disabled_my_option) + opt_silent= 0; + else + opt_silent++; + break; + case 'T': + { + struct my_tests_st *fptr; + + printf("All possible test names:\n\n"); + for (fptr= my_tests; fptr->name; fptr++) + printf("%s\n", fptr->name); + exit(0); + break; + } + case '?': + case 'I': /* Info */ + usage(); + exit(0); + break; + } + return 0; +} + +static void get_options(int *argc, char ***argv) +{ + int ho_error; + + if ((ho_error= handle_options(argc, argv, client_test_long_options, + get_one_option))) + exit(ho_error); + + if (tty_password) + opt_password= get_tty_password(NullS); + return; +} + +/* + Print the test output on successful execution before exiting +*/ + +static void print_test_output() +{ + if (opt_silent < 3) + { + fprintf(stdout, "\n\n"); + fprintf(stdout, "All '%d' tests were successful (in '%d' iterations)", + test_count-1, opt_count); + fprintf(stdout, "\n Total execution time: %g SECS", total_time); + if (opt_count > 1) + fprintf(stdout, " (Avg: %g SECS)", total_time/opt_count); + + fprintf(stdout, "\n\n!!! SUCCESS !!!\n"); + } +} + + +/*************************************************************************** + main routine +***************************************************************************/ + + +int main(int argc, char **argv) +{ + struct my_tests_st *fptr; + + DEBUGGER_OFF; + MY_INIT(argv[0]); + + load_defaults("my", client_test_load_default_groups, &argc, &argv); + defaults_argv= argv; + get_options(&argc, &argv); + + client_connect(); /* connect to server */ + + total_time= 0; + for (iter_count= 1; iter_count <= opt_count; iter_count++) + { + /* Start of tests */ + test_count= 1; + start_time= time((time_t *)0); + if (!argc) + { + for (fptr= my_tests; fptr->name; fptr++) + (*fptr->function)(); + } + else + { + for ( ; *argv ; argv++) + { + for (fptr= my_tests; fptr->name; fptr++) + { + if (!strcmp(fptr->name, *argv)) + { + (*fptr->function)(); + break; + } + } + if (!fptr->name) + { + fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv); + fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n", + my_progname); + client_disconnect(); + free_defaults(defaults_argv); + exit(1); + } + } + } + + end_time= time((time_t *)0); + total_time+= difftime(end_time, start_time); + + /* End of tests */ + } + + client_disconnect(); /* disconnect from server */ + free_defaults(defaults_argv); + print_test_output(); + my_end(0); + + exit(0); +} |