1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-21 01:27:14 +02:00

Add MariaDB Connector/C as a built-in alternative (v3.2.3).

This commit is contained in:
Sandu Liviu Catalin
2021-09-21 20:59:01 +03:00
parent f192767853
commit b4bf96ce4b
372 changed files with 90819 additions and 11 deletions

View File

@ -0,0 +1,67 @@
# Copyright (C) 2008 Sun Microsystems, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
IF(SKIP_TESTS)
RETURN()
ENDIF()
ENABLE_TESTING()
INCLUDE_DIRECTORIES(${CC_SOURCE_DIR}/include
${CC_BINARY_DIR}/include
${CC_SOURCE_DIR}/unittest/mytap
${CC_SOURCE_DIR}/unittest/libmariadb)
ADD_DEFINITIONS(-DLIBMARIADB)
SET(API_TESTS "conc336" "bulk1" "performance" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs" "sp" "result" "connection" "misc" "ps_new" "thread" "features-10_2" "bulk1")
IF(WITH_DYNCOL)
SET(API_TESTS ${API_TESTS} "dyncol")
ENDIF()
SET(API_TESTS ${API_TESTS} "async")
#exclude following tests from ctests, since we need to run them maually with different credentials
SET(MANUAL_TESTS "t_aurora" "t_conc173" "rpl_api")
# Get finger print from server certificate
IF(WITH_SSL)
IF(CERT_PATH AND NOT DEFINED ENV{TRAVIS})
SET(API_TESTS ${API_TESTS} "ssl")
IF(WIN32)
STRING(REPLACE "\\" "\\\\" CERT_PATH ${CERT_PATH})
ENDIF()
ADD_DEFINITIONS(-DCERT_PATH="${CERT_PATH}")
ENDIF()
ENDIF()
ADD_LIBRARY(ma_getopt ma_getopt.c)
FOREACH(API_TEST ${API_TESTS})
IF (NOT TARGET ${API_TEST})
ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c)
ENDIF()
TARGET_LINK_LIBRARIES(${API_TEST} cctap ma_getopt mariadbclient)
ADD_TEST(${API_TEST} ${EXECUTABLE_OUTPUT_PATH}/${API_TEST})
IF(${API_TEST} STREQUAL "cursor" OR ${API_TEST} STREQUAL "ps_new")
SET_TESTS_PROPERTIES(${API_TEST} PROPERTIES TIMEOUT 360)
ELSE()
SET_TESTS_PROPERTIES(${API_TEST} PROPERTIES TIMEOUT 180)
ENDIF()
ENDFOREACH(API_TEST)
FOREACH(API_TEST ${MANUAL_TESTS})
ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c)
TARGET_LINK_LIBRARIES(${API_TEST} cctap ma_getopt mariadbclient)
ENDFOREACH()

271
vendor/MDBC/unittest/libmariadb/async.c vendored Normal file
View File

@ -0,0 +1,271 @@
/*
Copyright 2011 Kristian Nielsen and Monty Program Ab.
This file is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU General Public License
along with this. If not, see <http://www.gnu.org/licenses/>.
*/
#include "my_test.h"
#include "ma_common.h"
#ifndef _WIN32
#include <poll.h>
#else
#include <winsock2.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <mysql.h>
my_bool skip_async= 0;
static int test_async(MYSQL *mysql)
{
int type;
mariadb_get_info(mysql, MARIADB_CONNECTION_PVIO_TYPE, &type);
if (type > MARIADB_CONNECTION_TCP)
{
skip_async= 1;
diag("Asnyc IO not supported");
}
return OK;
}
static int
wait_for_mysql(MYSQL *mysql, int status)
{
#ifdef _WIN32
fd_set rs, ws, es;
int res;
struct timeval tv, *timeout;
my_socket s= mysql_get_socket(mysql);
FD_ZERO(&rs);
FD_ZERO(&ws);
FD_ZERO(&es);
if (status & MYSQL_WAIT_READ)
FD_SET(s, &rs);
if (status & MYSQL_WAIT_WRITE)
FD_SET(s, &ws);
if (status & MYSQL_WAIT_EXCEPT)
FD_SET(s, &es);
if (status & MYSQL_WAIT_TIMEOUT)
{
tv.tv_sec= mysql_get_timeout_value(mysql);
tv.tv_usec= 0;
timeout= &tv;
}
else
timeout= NULL;
res= select(1, &rs, &ws, &es, timeout);
if (res == 0)
return MYSQL_WAIT_TIMEOUT;
else if (res == SOCKET_ERROR)
{
/*
In a real event framework, we should handle errors and re-try the select.
*/
return MYSQL_WAIT_TIMEOUT;
}
else
{
int status= 0;
if (FD_ISSET(s, &rs))
status|= MYSQL_WAIT_READ;
if (FD_ISSET(s, &ws))
status|= MYSQL_WAIT_WRITE;
if (FD_ISSET(s, &es))
status|= MYSQL_WAIT_EXCEPT;
return status;
}
#else
struct pollfd pfd;
int timeout;
int res= -1;
pfd.fd= mysql_get_socket(mysql);
pfd.events=
(status & MYSQL_WAIT_READ ? POLLIN : 0) |
(status & MYSQL_WAIT_WRITE ? POLLOUT : 0) |
(status & MYSQL_WAIT_EXCEPT ? POLLPRI : 0);
if (status & MYSQL_WAIT_TIMEOUT)
{
timeout= mysql_get_timeout_value_ms(mysql);
}
else
timeout= -1;
do {
res= poll(&pfd, 1, timeout);
} while (res == -1 && errno == EINTR);
if (res == 0)
return MYSQL_WAIT_TIMEOUT;
else if (res < 0)
{
/*
In a real event framework, we should handle EINTR and re-try the poll.
*/
return MYSQL_WAIT_TIMEOUT;
}
else
{
int status= 0;
if (pfd.revents & POLLIN)
status|= MYSQL_WAIT_READ;
if (pfd.revents & POLLOUT)
status|= MYSQL_WAIT_WRITE;
if (pfd.revents & POLLPRI)
status|= MYSQL_WAIT_EXCEPT;
return status;
}
#endif
}
static int async1(MYSQL *unused __attribute__((unused)))
{
int err= 0, rc;
MYSQL mysql, *ret;
MYSQL_RES *res;
MYSQL_ROW row;
int status;
uint default_timeout;
int i;
if (skip_async)
return SKIP;
for (i=0; i < 100; i++)
{
mysql_init(&mysql);
rc= mysql_options(&mysql, MYSQL_OPT_NONBLOCK, 0);
check_mysql_rc(rc, (MYSQL *)&mysql);
/* set timeouts to 300 microseconds */
default_timeout= 3;
mysql_options(&mysql, MYSQL_OPT_READ_TIMEOUT, &default_timeout);
mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, &default_timeout);
mysql_options(&mysql, MYSQL_OPT_WRITE_TIMEOUT, &default_timeout);
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "myapp");
if (force_tls)
mysql_ssl_set(&mysql, NULL, NULL, NULL, NULL,NULL);
/* Returns 0 when done, else flag for what to wait for when need to block. */
status= mysql_real_connect_start(&ret, &mysql, hostname, username, password, schema, port, socketname, 0);
while (status)
{
status= wait_for_mysql(&mysql, status);
status= mysql_real_connect_cont(&ret, &mysql, status);
}
if (!ret)
{
diag("Error: %s", mysql_error(&mysql));
FAIL_IF(!ret, "Failed to mysql_real_connect()");
}
if (force_tls && !mysql_get_ssl_cipher(&mysql))
{
diag("Error: No tls connection");
return FAIL;
}
status= mysql_real_query_start(&err, &mysql, SL("SHOW STATUS"));
while (status)
{
status= wait_for_mysql(&mysql, status);
status= mysql_real_query_cont(&err, &mysql, status);
}
FAIL_IF(err, "mysql_real_query() returns error");
/* This method cannot block. */
res= mysql_use_result(&mysql);
FAIL_IF(!res, "mysql_use_result() returns error");
for (;;)
{
status= mysql_fetch_row_start(&row, res);
while (status)
{
status= wait_for_mysql(&mysql, status);
status= mysql_fetch_row_cont(&row, res, status);
}
if (!row)
break;
}
FAIL_IF(mysql_errno(&mysql), "Got error while retrieving rows");
mysql_free_result(res);
/*
mysql_close() sends a COM_QUIT packet, and so in principle could block
waiting for the socket to accept the data.
In practise, for many applications it will probably be fine to use the
blocking mysql_close().
*/
status= mysql_close_start(&mysql);
while (status)
{
status= wait_for_mysql(&mysql, status);
status= mysql_close_cont(&mysql, status);
}
}
return OK;
}
static int test_conc131(MYSQL *unused __attribute__((unused)))
{
int rc;
/* this test needs to run under valgrind */
MYSQL *mysql;
if (skip_async)
return SKIP;
mysql= mysql_init(NULL);
rc= mysql_options(mysql, MYSQL_OPT_NONBLOCK, 0);
check_mysql_rc(rc, mysql);
mysql_close(mysql);
return OK;
}
static int test_conc129(MYSQL *unused __attribute__((unused)))
{
MYSQL *mysql;
if (skip_async)
return SKIP;
mysql= mysql_init(NULL);
FAIL_IF(mysql_close_start(mysql), "No error expected");
return OK;
}
struct my_tests_st my_tests[] = {
{"test_async", test_async, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"async1", async1, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc131", test_conc131, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"test_conc129", test_conc129, TEST_CONNECTION_NONE, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

View File

@ -0,0 +1,843 @@
/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
Some basic tests of the client API.
*/
#include "my_test.h"
#include "ma_common.h"
static int test_conc75(MYSQL *my)
{
int rc;
MYSQL *mysql;
int i;
my_bool reconnect= 1;
SKIP_SKYSQL;
SKIP_MAXSCALE;
mysql= mysql_init(NULL);
mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
my_test_connect(mysql, hostname, username, password, schema, port, socketname, 0| CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS a");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE a (a varchar(200))");
check_mysql_rc(rc, mysql);
rc= mysql_set_character_set(mysql, "utf8");
check_mysql_rc(rc, mysql);
for (i=0; i < 10; i++)
{
ulong thread_id= mysql_thread_id(mysql);
/* force reconnect */
mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
diag("killing connection");
mysql_kill(my, thread_id);
mysql_ping(mysql);
rc= mysql_query(mysql, "load data local infile './nonexistingfile.csv' into table a (`a`)");
FAIL_IF(!test(mysql->options.client_flag | CLIENT_LOCAL_FILES), "client_flags not correct");
diag("thread1: %ld %ld", thread_id, mysql_thread_id(mysql));
FAIL_IF(thread_id == mysql_thread_id(mysql), "new thread id expected");
//diag("cs: %s", mysql->charset->csname);
//FAIL_IF(strcmp(mysql->charset->csname, "utf8"), "wrong character set");
}
rc= mysql_query(mysql, "DROP TABLE IF EXISTS a");
check_mysql_rc(rc, mysql);
mysql_close(mysql);
return OK;
}
static int test_conc74(MYSQL *unused __attribute__((unused)))
{
int rc;
MYSQL *mysql;
mysql= mysql_init(NULL);
if (!my_test_connect(mysql, hostname, username, password, schema, port, socketname, 0| CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS))
{
diag("Error: %s", mysql_error(mysql));
mysql_close(mysql);
return FAIL;
}
rc= mysql_query(mysql, "DROP TABLE IF EXISTS a");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE a (a varchar(200))");
check_mysql_rc(rc, mysql);
mysql->options.client_flag&= ~CLIENT_LOCAL_FILES;
rc= mysql_query(mysql, "load data local infile './nonexistingfile.csv' into table a (`a`)");
FAIL_IF(!rc, "Error expected");
rc= mysql_query(mysql, "DROP TABLE IF EXISTS a");
check_mysql_rc(rc, mysql);
mysql_close(mysql);
return OK;
}
static int test_conc71(MYSQL *my)
{
int rc;
MYSQL *mysql;
/* uncomment if you want to test manually */
return SKIP;
mysql= mysql_init(NULL);
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "utf8");
mysql_options(mysql, MYSQL_OPT_COMPRESS, 0);
mysql_options(mysql, MYSQL_INIT_COMMAND, "/*!40101 SET SQL_MODE='' */");
mysql_options(mysql, MYSQL_INIT_COMMAND, "/*!40101 set @@session.wait_timeout=28800 */");
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
port, socketname, 0), mysql_error(my));
diag("kill server");
rc= mysql_query(mysql, "SELECT 'foo' FROM DUAL");
check_mysql_rc(rc, mysql);
mysql_close(mysql);
return OK;
}
static int test_conc70(MYSQL *my)
{
int rc;
MYSQL_RES *res;
MYSQL_ROW row;
MYSQL *mysql;
SKIP_CONNECTION_HANDLER;
SKIP_SKYSQL;
SKIP_MAXSCALE;
mysql= mysql_init(NULL);
rc= mysql_query(my, "SET @a:=@@max_allowed_packet");
check_mysql_rc(rc, my);
mysql_query(my, "SET global max_allowed_packet=1024*1024*22");
check_mysql_rc(rc, my);
mysql_options(mysql, MYSQL_OPT_COMPRESS, (void *)1);
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
port, socketname, 0), mysql_error(my));
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1 (a LONGBLOB) engine=MyISAM");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (REPEAT('A', 1024 * 1024 * 20))");
check_mysql_rc(rc, mysql);
if (mysql_warning_count(mysql))
{
diag("server doesn't accept package size");
return SKIP;
}
rc= mysql_query(mysql, "SELECT a FROM t1");
check_mysql_rc(rc, mysql);
if (!(res= mysql_store_result(mysql)))
{
diag("Error: %s", mysql_error(mysql));
return FAIL;
}
row= mysql_fetch_row(res);
diag("Length: %ld", (long)strlen(row[0]));
FAIL_IF(strlen(row[0]) != 1024 * 1024 * 20, "Wrong length");
mysql_free_result(res);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
mysql_close(mysql);
rc= mysql_query(my, "SET global max_allowed_packet=@a");
check_mysql_rc(rc, my);
return OK;
}
static int test_conc68(MYSQL *my)
{
int rc;
MYSQL_RES *res;
MYSQL_ROW row;
MYSQL *mysql;
SKIP_CONNECTION_HANDLER;
SKIP_SKYSQL;
SKIP_MAXSCALE;
mysql= mysql_init(NULL);
rc= mysql_query(my, "SET @a:=@@max_allowed_packet");
check_mysql_rc(rc, my);
mysql_query(my, "SET global max_allowed_packet=1024*1024*22");
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
port, socketname, 0), mysql_error(my));
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1 (a LONGBLOB) ENGINE=MyISAM");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (REPEAT('A', 1024 * 1024 * 20))");
check_mysql_rc(rc, mysql);
if (mysql_warning_count(mysql))
{
diag("server doesn't accept package size");
return SKIP;
}
rc= mysql_query(mysql, "SELECT a FROM t1");
check_mysql_rc(rc, mysql);
if (!(res= mysql_store_result(mysql)))
{
diag("Error: %s", mysql_error(mysql));
return FAIL;
}
row= mysql_fetch_row(res);
diag("Length: %ld", (long)strlen(row[0]));
FAIL_IF(strlen(row[0]) != 1024 * 1024 * 20, "Wrong length");
mysql_free_result(res);
mysql_close(mysql);
rc= mysql_query(my, "SET global max_allowed_packet=@a");
check_mysql_rc(rc, my);
return OK;
}
static int basic_connect(MYSQL *unused __attribute__((unused)))
{
MYSQL_ROW row;
MYSQL_RES *res;
MYSQL_FIELD *field;
int rc;
MYSQL *my;
my= mysql_init(NULL);
FAIL_IF(!my, "mysql_init() failed");
FAIL_IF(!my_test_connect(my, hostname, username, password, schema,
port, socketname, 0), mysql_error(my));
rc= mysql_query(my, "SELECT @@version");
check_mysql_rc(rc, my);
res= mysql_store_result(my);
FAIL_IF(!res, mysql_error(my));
field= mysql_fetch_fields(res);
FAIL_IF(!field, "couldn't fetch field");
while ((row= mysql_fetch_row(res)) != NULL)
{
FAIL_IF(mysql_num_fields(res) != 1, "Got the wrong number of fields");
}
FAIL_IF(mysql_errno(my), mysql_error(my));
mysql_free_result(res);
mysql_close(my);
return OK;
}
static int use_utf8(MYSQL *my)
{
MYSQL_ROW row;
MYSQL_RES *res;
int rc;
/* Make sure that we actually ended up with utf8. */
rc= mysql_query(my, "SELECT @@character_set_connection");
check_mysql_rc(rc, my);
res= mysql_store_result(my);
FAIL_IF(!res, mysql_error(my));
while ((row= mysql_fetch_row(res)) != NULL)
{
FAIL_IF(strncmp(row[0], "utf8", 4), "wrong character set");
}
FAIL_IF(mysql_errno(my), mysql_error(my));
mysql_free_result(res);
return OK;
}
int client_query(MYSQL *mysql) {
int rc;
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1("
"id int primary key auto_increment, "
"name varchar(20))");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1(id int, name varchar(20))");
FAIL_IF(!rc, "Error expected");
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('mysql')");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('monty')");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('venu')");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "UPDATE t1 SET name= 'updated' "
"WHERE name= 'deleted'");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "UPDATE t1 SET id= 3 WHERE name= 'updated'");
FAIL_IF(!rc, "Error expected");
rc= mysql_query(mysql, "drop table t1");
check_mysql_rc(rc, mysql);
return OK;
}
static int test_bug12001(MYSQL *mysql)
{
MYSQL_RES *result;
const char *query= "DROP TABLE IF EXISTS test_table;"
"CREATE TABLE test_table(id INT);"
"INSERT INTO test_table VALUES(10);"
"UPDATE test_table SET id=20 WHERE id=10;"
"SELECT * FROM test_table;"
"INSERT INTO non_existent_table VALUES(11);";
int rc, res;
rc= mysql_query(mysql, query);
check_mysql_rc(rc, mysql);
do
{
if (mysql_field_count(mysql) &&
(result= mysql_use_result(mysql)))
{
mysql_free_result(result);
}
}
while (!(res= mysql_next_result(mysql)));
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_table");
check_mysql_rc(rc, mysql);
FAIL_UNLESS(res==1, "res != 1");
return OK;
}
/* connection options */
struct my_option_st opt_utf8[] = {
{MYSQL_SET_CHARSET_NAME, (char *)"utf8"},
{0, NULL}
};
static int test_bad_union(MYSQL *mysql)
{
MYSQL_STMT *stmt;
int rc;
const char *query= "SELECT 1, 2 union SELECT 1";
stmt= mysql_stmt_init(mysql);
FAIL_IF(!stmt, mysql_error(mysql));
rc= mysql_stmt_prepare(stmt, SL(query));
FAIL_UNLESS(rc && mysql_errno(mysql) == 1222, "Error expected");
mysql_stmt_close(stmt);
return OK;
}
/*
Test that mysql_insert_id() behaves as documented in our manual
*/
static int test_mysql_insert_id(MYSQL *mysql)
{
unsigned long long res;
int rc;
if (mysql_get_server_version(mysql) < 50100) {
diag("Test requires MySQL Server version 5.1 or above");
return SKIP;
}
rc= mysql_query(mysql, "drop table if exists t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "drop table if exists t2");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "drop table if exists t3");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "drop table if exists t4");
check_mysql_rc(rc, mysql);
/* table without auto_increment column */
rc= mysql_query(mysql, "create table t1 (f1 int, f2 varchar(255), key(f1))");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create table t2 (f1 int not null primary key auto_increment, f2 varchar(255))");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create table t3 (f1 int not null primary key auto_increment, f2 varchar(255)) engine=MyISAM");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create table t4 (f1 int not null primary key "
"auto_increment, f2 varchar(200), unique (f2)) engine=MyISAM");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "FLUSH TABLES");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "START TRANSACTION");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "insert into t1 values (1,'a')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
rc= mysql_query(mysql, "insert into t1 values (null,'b')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
rc= mysql_query(mysql, "insert into t1 select 5,'c'");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
/*
Test for bug #34889: mysql_client_test::test_mysql_insert_id test fails
sporadically
*/
rc= mysql_query(mysql, "insert into t2 values (null,'b')");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "insert into t1 select 5,'c'");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
rc= mysql_query(mysql, "insert into t1 select null,'d'");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
rc= mysql_query(mysql, "insert into t1 values (null,last_insert_id(300))");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 300, "");
rc= mysql_query(mysql, "insert into t1 select null,last_insert_id(400)");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
/*
Behaviour change: old code used to return 0; but 400 is consistent
with INSERT VALUES, and the manual's section of mysql_insert_id() does not
say INSERT SELECT should be different.
*/
FAIL_UNLESS(res == 400, "");
/* table with auto_increment column */
rc= mysql_query(mysql, "insert into t3 values (1,'a')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 1, "");
/* this should not influence next INSERT if it doesn't have auto_inc */
rc= mysql_query(mysql, "insert into t1 values (10,'e')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
rc= mysql_query(mysql, "insert into t3 values (null,'b')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 2, "");
rc= mysql_query(mysql, "insert into t3 select 5,'c'");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
/*
Manual says that for multirow insert this should have been 5, but does not
say for INSERT SELECT. This is a behaviour change: old code used to return
0. We try to be consistent with INSERT VALUES.
*/
FAIL_UNLESS(res == 5, "");
rc= mysql_query(mysql, "insert into t3 select null,'d'");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 6, "");
/* with more than one row */
rc= mysql_query(mysql, "insert into t3 values (10,'a'),(11,'b')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 11, "");
rc= mysql_query(mysql, "insert into t3 select 12,'a' union select 13,'b'");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
/*
Manual says that for multirow insert this should have been 13, but does
not say for INSERT SELECT. This is a behaviour change: old code used to
return 0. We try to be consistent with INSERT VALUES.
*/
FAIL_UNLESS(res == 13, "");
rc= mysql_query(mysql, "insert into t3 values (null,'a'),(null,'b')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 14, "");
rc= mysql_query(mysql, "insert into t3 select null,'a' union select null,'b'");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 16, "");
rc= mysql_query(mysql, "insert into t3 select 12,'a' union select 13,'b'");
FAIL_IF(!rc, "Error expected");
rc= mysql_query(mysql, "insert ignore into t3 select 12,'a' union select 13,'b'");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
rc= mysql_query(mysql, "insert into t3 values (12,'a'),(13,'b')");
FAIL_IF(!rc, "Error expected");
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
rc= mysql_query(mysql, "insert ignore into t3 values (12,'a'),(13,'b')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
/* mixing autogenerated and explicit values */
rc= mysql_query(mysql, "insert into t3 values (null,'e'),(12,'a'),(13,'b')");
FAIL_IF(!rc, "Error expected");
rc= mysql_query(mysql, "insert into t3 values (null,'e'),(12,'a'),(13,'b'),(25,'g')");
FAIL_IF(!rc, "Error expected");
rc= mysql_query(mysql, "insert into t3 values (null,last_insert_id(300))");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
/*
according to the manual, this might be 20 or 300, but it looks like
auto_increment column takes priority over last_insert_id().
*/
diag("res: %lld", res);
FAIL_UNLESS(res == 20, "");
/* If first autogenerated number fails and 2nd works: */
rc= mysql_query(mysql, "insert into t4 values (null,'e')");
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 1, "");
rc= mysql_query(mysql, "insert ignore into t4 values (null,'e'),(null,'a'),(null,'e')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 2, "");
/* If autogenerated fails and explicit works: */
rc= mysql_query(mysql, "insert ignore into t4 values (null,'e'),(12,'c'),(null,'d')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
/*
Behaviour change: old code returned 3 (first autogenerated, even if it
fails); we now return first successful autogenerated.
*/
FAIL_UNLESS(res == 13, "");
/* UPDATE may update mysql_insert_id() if it uses LAST_INSERT_ID(#) */
rc= mysql_query(mysql, "update t4 set f1=14 where f1=12");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
rc= mysql_query(mysql, "update t4 set f1=0 where f1=14");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
rc= mysql_query(mysql, "update t4 set f2=last_insert_id(372) where f1=0");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 372, "");
/* check that LAST_INSERT_ID() does not update mysql_insert_id(): */
rc= mysql_query(mysql, "insert into t4 values (null,'g')");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 15, "");
rc= mysql_query(mysql, "update t4 set f2=(@li:=last_insert_id()) where f1=15");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 0, "");
/*
Behaviour change: now if ON DUPLICATE KEY UPDATE updates a row,
mysql_insert_id() returns the id of the row, instead of not being
affected.
*/
rc= mysql_query(mysql, "insert into t4 values (null,@li) on duplicate key "
"update f2=concat('we updated ',f2)");
check_mysql_rc(rc, mysql);
res= mysql_insert_id(mysql);
FAIL_UNLESS(res == 15, "");
rc= mysql_query(mysql, "drop table t1,t2,t3,t4");
check_mysql_rc(rc, mysql);
return OK;
}
/* Test simple select to debug */
static int test_select_direct(MYSQL *mysql)
{
int rc;
MYSQL_RES *result;
rc= mysql_autocommit(mysql, TRUE);
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE test_select(id int, id1 tinyint, "
" id2 float, "
" id3 double, "
" name varchar(50))");
check_mysql_rc(rc, mysql);
/* insert a row and commit the transaction */
rc= mysql_query(mysql, "INSERT INTO test_select VALUES(10, 5, 2.3, 4.5, 'venu')");
check_mysql_rc(rc, mysql);
rc= mysql_commit(mysql);
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SELECT * FROM test_select");
check_mysql_rc(rc, mysql);
/* get the result */
result= mysql_store_result(mysql);
FAIL_IF(!result, "Invalid result set");
mysql_free_result(result);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_select");
check_mysql_rc(rc, mysql);
return OK;
}
/*
Ensure we execute the status code while testing
*/
static int test_status(MYSQL *mysql)
{
mysql_stat(mysql);
check_mysql_rc(mysql_errno(mysql), mysql);
return OK;
}
static int bug_conc1(MYSQL *mysql)
{
my_test_connect(mysql, hostname, username, password, schema,
port, socketname, 0);
diag("errno: %d", mysql_errno(mysql));
FAIL_IF(mysql_errno(mysql) != CR_ALREADY_CONNECTED,
"Expected errno=CR_ALREADY_CONNECTED");
return OK;
}
static int test_options_initcmd(MYSQL *unused __attribute__((unused)))
{
MYSQL *mysql= mysql_init(NULL);
MYSQL_RES *res;
int rc;
mysql_options(mysql, MYSQL_INIT_COMMAND, "DROP TABLE IF EXISTS t1; CREATE TABLE t1 (a int)");
mysql_options(mysql, MYSQL_INIT_COMMAND, "INSERT INTO t1 VALUES (1),(2),(3)");
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
port, socketname,
CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS), mysql_error(mysql));
rc= mysql_query(mysql, "SELECT a FROM t1");
check_mysql_rc(rc, mysql);
res= mysql_store_result(mysql);
FAIL_IF(mysql_num_rows(res) != 3, "Expected 3 rows");
mysql_free_result(res);
rc= mysql_query(mysql, "DROP TABLE t1");
check_mysql_rc(rc, mysql);
mysql_close(mysql);
return OK;
}
static int test_extended_init_values(MYSQL *unused __attribute__((unused)))
{
MYSQL *mysql= mysql_init(NULL);
mysql_options(mysql, MYSQL_DEFAULT_AUTH, "unknown");
FAIL_IF(strcmp(mysql->options.extension->default_auth, "unknown"), "option not set");
mysql_options(mysql, MYSQL_PLUGIN_DIR, "/tmp/foo");
FAIL_IF(strcmp(mysql->options.extension->plugin_dir, "/tmp/foo"), "option not set");
mysql_close(mysql);
return OK;
}
static int test_reconnect_maxpackage(MYSQL *unused __attribute__((unused)))
{
int rc;
ulong max_packet= 0;
MYSQL *mysql;
MYSQL_RES *res;
MYSQL_ROW row;
char *query;
my_bool reconnect= 1;
SKIP_CONNECTION_HANDLER;
mysql= mysql_init(NULL);
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
port, socketname,
CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS), mysql_error(mysql));
mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
rc= mysql_query(mysql, "SELECT @@max_allowed_packet");
check_mysql_rc(rc, mysql);
res= mysql_store_result(mysql);
row= mysql_fetch_row(res);
max_packet= atol(row[0]);
diag("max_allowed_packet=%lu", max_packet);
mysql_free_result(res);
query= (char *)malloc(max_packet + 30);
memset(query, 0, max_packet + 30);
strcpy(query, "SELECT '");
memset(query + 8, 'A', max_packet);
strcat(query, "' FROM DUAL");
rc= mysql_query(mysql, query);
free(query);
if (!rc)
{
diag("expected error");
mysql_close(mysql);
return FAIL;
}
else
diag("Error (expected): %s", mysql_error(mysql));
rc= mysql_ping(mysql);
/* if the server is under load, poll might not report closed
socket since FIN packet came too late */
if (rc)
rc= mysql_ping(mysql);
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SELECT @@max_allowed_packet");
check_mysql_rc(rc, mysql);
res= mysql_store_result(mysql);
row= mysql_fetch_row(res);
max_packet= atol(row[0]);
diag("max_allowed_packet=%lu", max_packet);
mysql_free_result(res);
mysql_close(mysql);
return OK;
}
static int test_compressed(MYSQL *unused __attribute__((unused)))
{
int rc;
MYSQL *mysql= mysql_init(NULL);
MYSQL_RES *res;
my_bool reconnect= 1;
mysql_options(mysql, MYSQL_OPT_COMPRESS, (void *)1);
FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema,
port, socketname,
CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS), mysql_error(mysql));
mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
rc= mysql_query(mysql, "SHOW VARIABLES");
check_mysql_rc(rc, mysql);
if ((res= mysql_store_result(mysql)))
mysql_free_result(res);
mysql_close(mysql);
return OK;
}
struct my_tests_st my_tests[] = {
{"test_conc75", test_conc75, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc74", test_conc74, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc71", test_conc71, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc70", test_conc70, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc68", test_conc68, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_compressed", test_compressed, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"test_reconnect_maxpackage", test_reconnect_maxpackage, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"basic_connect", basic_connect, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"use_utf8", use_utf8, TEST_CONNECTION_NEW, 0, opt_utf8, NULL},
{"client_query", client_query, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_bad_union", test_bad_union, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_select_direct", test_select_direct, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_mysql_insert_id", test_mysql_insert_id, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_bug12001", test_bug12001, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
{"test_status", test_status, TEST_CONNECTION_NEW, CLIENT_MULTI_STATEMENTS, NULL, NULL},
{"bug_conc1", bug_conc1, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"test_options_initcmd", test_options_initcmd, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"test_extended_init_values", test_extended_init_values, TEST_CONNECTION_NONE, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
diag("user: %s", username);
run_tests(my_tests);
return(exit_status());
}

1100
vendor/MDBC/unittest/libmariadb/bulk1.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,846 @@
/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "my_test.h"
/*
test gbk charset escaping
The important part is that 0x27 (') is the second-byte in a invalid
two-byte GBK character here. But 0xbf5c is a valid GBK character, so
it needs to be escaped as 0x5cbf27
*/
#define TEST_BUG8378_IN "\xef\xbb\xbf\x27\xbf\x10"
#define TEST_BUG8378_OUT "\xef\xbb\x5c\xbf\x5c\x27\x5c\xbf\x10"
/* set connection options */
struct my_option_st opt_bug8378[] = {
{MYSQL_SET_CHARSET_NAME, (char *) "gbk"},
{0, NULL}
};
int bug_8378(MYSQL *mysql) {
int rc, len;
char out[9], buf[256];
MYSQL_RES *res;
MYSQL_ROW row;
len= mysql_real_escape_string(mysql, out, TEST_BUG8378_IN, 4);
FAIL_IF(memcmp(out, TEST_BUG8378_OUT, len), "wrong result");
sprintf(buf, "SELECT '%s' FROM DUAL", TEST_BUG8378_OUT);
rc= mysql_query(mysql, buf);
check_mysql_rc(rc, mysql);
if ((res= mysql_store_result(mysql))) {
row= mysql_fetch_row(res);
if (memcmp(row[0], TEST_BUG8378_IN, 4)) {
mysql_free_result(res);
return FAIL;
}
mysql_free_result(res);
} else
return FAIL;
return OK;
}
int test_client_character_set(MYSQL *mysql)
{
MY_CHARSET_INFO cs;
char *csname= (char*) "latin2";
char *csdefault= (char*)mysql_character_set_name(mysql);
FAIL_IF(mysql_set_character_set(mysql, csname), mysql_error(mysql));
mysql_get_character_set_info(mysql, &cs);
FAIL_IF(strcmp(cs.csname, "latin2") || strcmp(cs.name, "latin2_general_ci"),
"Character set != latin2");
FAIL_IF(mysql_set_character_set(mysql, csdefault), mysql_error(mysql));
return OK;
}
/*
* Regression test for bug #10214
*
* Test escaping with NO_BACKSLASH_ESCAPES
*
*/
int bug_10214(MYSQL *mysql)
{
int len, rc;
char out[8];
/* reset sql_mode */
rc= mysql_query(mysql, "SET sql_mode=''");
check_mysql_rc(rc, mysql);
len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
FAIL_IF(memcmp(out, "a\\'b\\\\c", len), "wrong result");
rc= mysql_query(mysql, "set sql_mode='NO_BACKSLASH_ESCAPES'");
check_mysql_rc(rc, mysql);
FAIL_IF(!(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES),
"wrong server status: NO_BACKSLASH_ESCAPES not set");
len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
FAIL_IF(memcmp(out, "a''b\\c", len), "wrong result");
return OK;
}
/*
* simple escaping of special chars
*/
int test_escaping(MYSQL *mysql)
{
int i= 0, rc, len;
char out[20];
const char *escape_chars[] = {"'", "\x0", "\n", "\r", "\\", "\0", NULL};
/* reset sql_mode, mysql_change_user call doesn't reset it */
rc= mysql_query(mysql, "SET sql_mode=''");
check_mysql_rc(rc, mysql);
while (escape_chars[i]) {
len= mysql_real_escape_string(mysql, out, escape_chars[i], 1);
FAIL_IF(len < 2, "Len < 2");
i++;
}
return OK;
}
/*
* server doesn't reset sql_mode after COM_CHANGE_USER
*/
int bug_41785(MYSQL *mysql)
{
char out[10];
int rc, len;
len= mysql_real_escape_string(mysql, out, "\\", 1);
FAIL_IF(len != 2, "len != 2");
rc= mysql_query(mysql, "SET SQL_MODE=NO_BACKSLASH_ESCAPES");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SET sql_mode=''");
check_mysql_rc(rc, mysql);
mysql_change_user(mysql, "root", "", "test");
len= mysql_real_escape_string(mysql, out, "\\", 1);
FAIL_IF(len != 2, "len != 2");
return OK;
}
static int test_conversion(MYSQL *mysql)
{
MYSQL_STMT *stmt;
const char *stmt_text;
int rc;
MYSQL_BIND my_bind[1];
uchar buff[4];
ulong length;
stmt_text= "DROP TABLE IF EXISTS t1";
rc= mysql_real_query(mysql, SL(stmt_text));
check_mysql_rc(rc, mysql);
stmt_text= "CREATE TABLE t1 (a TEXT) DEFAULT CHARSET latin1";
rc= mysql_real_query(mysql, SL(stmt_text));
check_mysql_rc(rc, mysql);
stmt_text= "SET character_set_connection=utf8, character_set_client=utf8, "
" character_set_results=latin1";
rc= mysql_real_query(mysql, SL(stmt_text));
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
FAIL_IF(!stmt, mysql_error(mysql));
stmt_text= "INSERT INTO t1 (a) VALUES (?)";
rc= mysql_stmt_prepare(stmt, SL(stmt_text));
check_stmt_rc(rc, stmt);
memset(my_bind, '\0', sizeof(my_bind));
my_bind[0].buffer= (char*) buff;
my_bind[0].length= &length;
my_bind[0].buffer_type= MYSQL_TYPE_STRING;
mysql_stmt_bind_param(stmt, my_bind);
buff[0]= (uchar) 0xC3;
buff[1]= (uchar) 0xA0;
length= 2;
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
stmt_text= "SELECT a FROM t1";
rc= mysql_stmt_prepare(stmt, SL(stmt_text));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
my_bind[0].buffer_length= sizeof(buff);
mysql_stmt_bind_result(stmt, my_bind);
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
FAIL_UNLESS(length == 1, "length != 1");
FAIL_UNLESS(buff[0] == 0xE0, "buff[0] != 0xE0");
rc= mysql_stmt_fetch(stmt);
FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
mysql_stmt_close(stmt);
stmt_text= "DROP TABLE t1";
rc= mysql_real_query(mysql, SL(stmt_text));
check_mysql_rc(rc, mysql);
stmt_text= "SET NAMES DEFAULT";
rc= mysql_real_query(mysql, SL(stmt_text));
check_mysql_rc(rc, mysql);
return OK;
}
static int test_bug27876(MYSQL *mysql)
{
int rc;
MYSQL_RES *result;
uchar utf8_func[] =
{
0xd1, 0x84, 0xd1, 0x83, 0xd0, 0xbd, 0xd0, 0xba,
0xd1, 0x86, 0xd0, 0xb8, 0xd0, 0xb9, 0xd0, 0xba,
0xd0, 0xb0,
0x00
};
uchar utf8_param[] =
{
0xd0, 0xbf, 0xd0, 0xb0, 0xd1, 0x80, 0xd0, 0xb0,
0xd0, 0xbc, 0xd0, 0xb5, 0xd1, 0x82, 0xd1, 0x8a,
0xd1, 0x80, 0x5f, 0xd0, 0xb2, 0xd0, 0xb5, 0xd1,
0x80, 0xd1, 0x81, 0xd0, 0xb8, 0xd1, 0x8f,
0x00
};
char query[500];
rc= mysql_query(mysql, "set names utf8");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "select version()");
check_mysql_rc(rc, mysql);
result= mysql_store_result(mysql);
FAIL_IF(!result, "Invalid result set");
mysql_free_result(result);
sprintf(query, "DROP FUNCTION IF EXISTS %s", (char*) utf8_func);
rc= mysql_query(mysql, query);
check_mysql_rc(rc, mysql);
sprintf(query,
"CREATE FUNCTION %s( %s VARCHAR(25))"
" RETURNS VARCHAR(25) DETERMINISTIC RETURN %s",
(char*) utf8_func, (char*) utf8_param, (char*) utf8_param);
rc= mysql_query(mysql, query);
check_mysql_rc(rc, mysql);
sprintf(query, "SELECT %s(VERSION())", (char*) utf8_func);
rc= mysql_query(mysql, query);
check_mysql_rc(rc, mysql);
result= mysql_store_result(mysql);
FAIL_IF(!result, "Invalid result set");
mysql_free_result(result);
sprintf(query, "DROP FUNCTION %s", (char*) utf8_func);
rc= mysql_query(mysql, query);
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "set names default");
check_mysql_rc(rc, mysql);
return OK;
}
static int test_ps_i18n(MYSQL *mysql)
{
MYSQL_STMT *stmt;
int rc;
const char *stmt_text;
MYSQL_BIND bind_array[2];
/* Represented as numbers to keep UTF8 tools from clobbering them. */
const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5";
const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3";
char buf1[16], buf2[16];
ulong buf1_len, buf2_len;
stmt_text= "DROP TABLE IF EXISTS t1";
rc= mysql_real_query(mysql, SL(stmt_text));
check_mysql_rc(rc, mysql);
/*
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, SL(stmt_text));
check_mysql_rc(rc, mysql);
stmt_text= "SET CHARACTER_SET_CLIENT=koi8r, "
"CHARACTER_SET_CONNECTION=cp1251, "
"CHARACTER_SET_RESULTS=koi8r";
rc= mysql_real_query(mysql, SL(stmt_text));
check_mysql_rc(rc, mysql);
memset(bind_array, '\0', sizeof(bind_array));
bind_array[0].buffer_type= MYSQL_TYPE_STRING;
bind_array[0].buffer= (void *) koi8;
bind_array[0].buffer_length= (unsigned long)strlen(koi8);
bind_array[1].buffer_type= MYSQL_TYPE_STRING;
bind_array[1].buffer= (void *) koi8;
bind_array[1].buffer_length= (unsigned long)strlen(koi8);
stmt= mysql_stmt_init(mysql);
check_stmt_rc(rc, stmt);
stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)";
rc= mysql_stmt_prepare(stmt, SL(stmt_text));
check_stmt_rc(rc, stmt);
mysql_stmt_bind_param(stmt, bind_array);
check_stmt_rc(rc, stmt);
// mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
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, SL(stmt_text));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
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_stmt_rc(rc, stmt);
FAIL_UNLESS(buf1_len == strlen(cp1251), "buf1_len != strlen(cp1251)");
FAIL_UNLESS(buf2_len == strlen(cp1251), "buf2_len != strlen(cp1251)");
FAIL_UNLESS(!memcmp(buf1, cp1251, buf1_len), "buf1 != cp1251");
FAIL_UNLESS(!memcmp(buf2, cp1251, buf1_len), "buf2 != cp1251");
rc= mysql_stmt_fetch(stmt);
FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
stmt_text= "DROP TABLE IF EXISTS t1";
rc= mysql_real_query(mysql, SL(stmt_text));
check_mysql_rc(rc, mysql);
/*
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, SL(stmt_text));
check_mysql_rc(rc, mysql);
stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)";
rc= mysql_stmt_prepare(stmt, SL(stmt_text));
check_stmt_rc(rc, stmt);
/* this data must be converted */
bind_array[0].buffer_type= MYSQL_TYPE_STRING;
bind_array[0].buffer= (void *) koi8;
bind_array[0].buffer_length= (unsigned long)strlen(koi8);
bind_array[1].buffer_type= MYSQL_TYPE_STRING;
bind_array[1].buffer= (void *) koi8;
bind_array[1].buffer_length= (unsigned long)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_stmt_rc(rc, stmt);
/* 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= (unsigned long)strlen(cp1251);
bind_array[1].buffer_type= MYSQL_TYPE_BLOB;
bind_array[1].buffer= (void *) cp1251;
bind_array[1].buffer_length= (unsigned long)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_stmt_rc(rc, stmt);
/* 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, SL(stmt_text));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
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)
{
FAIL_UNLESS(buf1_len == strlen(koi8), "buf1_len != strlen(koi8)");
FAIL_UNLESS(buf2_len == strlen(koi8), "buf2_len != strlen(koi8)");
FAIL_UNLESS(!memcmp(buf1, koi8, buf1_len), "buf1 != koi8");
FAIL_UNLESS(!memcmp(buf2, koi8, buf1_len), "buf2 != koi8");
}
FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
mysql_stmt_close(stmt);
stmt_text= "DROP TABLE t1";
rc= mysql_real_query(mysql, SL(stmt_text));
check_mysql_rc(rc, mysql);
stmt_text= "SET NAMES DEFAULT";
rc= mysql_real_query(mysql, SL(stmt_text));
check_mysql_rc(rc, mysql);
return OK;
}
/*
Bug#30472: libmysql doesn't reset charset, insert_id after succ.
mysql_change_user() call row insertions.
*/
static int bug30472_retrieve_charset_info(MYSQL *con,
char *character_set_name,
char *character_set_client,
char *character_set_results,
char *collation_connection)
{
MYSQL_RES *rs;
MYSQL_ROW row;
int rc;
/* Get the cached client character set name. */
strcpy(character_set_name, mysql_character_set_name(con));
/* Retrieve server character set information. */
rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_client'");
check_mysql_rc(rc, con);
rs= mysql_store_result(con);
FAIL_IF(!rs, "Invalid result set");
row= mysql_fetch_row(rs);
FAIL_IF(!row, "Couldn't fetch row");
strcpy(character_set_client, row[1]);
mysql_free_result(rs);
rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'");
check_mysql_rc(rc, con);
rs= mysql_store_result(con);
FAIL_IF(!rs, "Invalid result set");
row= mysql_fetch_row(rs);
FAIL_IF(!row, "Couldn't fetch row");
strcpy(character_set_results, row[1]);
mysql_free_result(rs);
rc= mysql_query(con, "SHOW VARIABLES LIKE 'collation_connection'");
check_mysql_rc(rc, con);
rs= mysql_store_result(con);
FAIL_IF(!rs, "Invalid result set");
row= mysql_fetch_row(rs);
FAIL_IF(!row, "Couldn't fetch row");
strcpy(collation_connection, row[1]);
mysql_free_result(rs);
return OK;
}
#define MY_CS_NAME_SIZE 32
static int test_bug30472(MYSQL *mysql)
{
int rc;
char character_set_name_1[MY_CS_NAME_SIZE];
char character_set_client_1[MY_CS_NAME_SIZE];
char character_set_results_1[MY_CS_NAME_SIZE];
char collation_connnection_1[MY_CS_NAME_SIZE];
char character_set_name_2[MY_CS_NAME_SIZE];
char character_set_client_2[MY_CS_NAME_SIZE];
char character_set_results_2[MY_CS_NAME_SIZE];
char collation_connnection_2[MY_CS_NAME_SIZE];
char character_set_name_3[MY_CS_NAME_SIZE];
char character_set_client_3[MY_CS_NAME_SIZE];
char character_set_results_3[MY_CS_NAME_SIZE];
char collation_connnection_3[MY_CS_NAME_SIZE];
char character_set_name_4[MY_CS_NAME_SIZE];
char character_set_client_4[MY_CS_NAME_SIZE];
char character_set_results_4[MY_CS_NAME_SIZE];
char collation_connnection_4[MY_CS_NAME_SIZE];
SKIP_MAXSCALE;
if (mysql_get_server_version(mysql) < 50100 || !is_mariadb)
{
diag("Test requires MySQL Server version 5.1 or above");
return SKIP;
}
/* Retrieve character set information. */
mysql_set_character_set(mysql, "latin1");
bug30472_retrieve_charset_info(mysql,
character_set_name_1,
character_set_client_1,
character_set_results_1,
collation_connnection_1);
/* Switch client character set. */
FAIL_IF(mysql_set_character_set(mysql, "ascii"),
"Setting cs to ascii failed");
/* Retrieve character set information. */
bug30472_retrieve_charset_info(mysql,
character_set_name_2,
character_set_client_2,
character_set_results_2,
collation_connnection_2);
/*
Check that
1) character set has been switched and
2) new character set is different from the original one.
*/
FAIL_UNLESS(strcmp(character_set_name_2, "ascii") == 0, "cs_name != ascii");
FAIL_UNLESS(strcmp(character_set_client_2, "ascii") == 0, "cs_client != ascii");
FAIL_UNLESS(strcmp(character_set_results_2, "ascii") == 0, "cs_result != ascii");
FAIL_UNLESS(strcmp(collation_connnection_2, "ascii_general_ci") == 0,
"collation != ascii_general_ci");
diag("%s %s", character_set_name_1, character_set_name_2);
FAIL_UNLESS(strcmp(character_set_name_1, character_set_name_2) != 0, "cs_name1 = cs_name2");
FAIL_UNLESS(strcmp(character_set_client_1, character_set_client_2) != 0, "cs_client1 = cs_client2");
FAIL_UNLESS(strcmp(character_set_results_1, character_set_results_2) != 0, "cs_result1 = cs_result2");
FAIL_UNLESS(strcmp(collation_connnection_1, collation_connnection_2) != 0, "collation1 = collation2");
/* Call mysql_change_user() with the same username, password, database. */
rc= mysql_change_user(mysql, username, password, (schema) ? schema : "test");
mysql_set_character_set(mysql, "latin1");
check_mysql_rc(rc, mysql);
/* Retrieve character set information. */
bug30472_retrieve_charset_info(mysql,
character_set_name_3,
character_set_client_3,
character_set_results_3,
collation_connnection_3);
/* Check that character set information has been reset. */
FAIL_UNLESS(strcmp(character_set_name_1, character_set_name_3) == 0, "cs_name1 != cs_name3");
FAIL_UNLESS(strcmp(character_set_client_1, character_set_client_3) == 0, "cs_client1 != cs_client3");
FAIL_UNLESS(strcmp(character_set_results_1, character_set_results_3) == 0, "cs_result1 != cs_result3");
FAIL_UNLESS(strcmp(collation_connnection_1, collation_connnection_3) == 0, "collation1 != collation3");
/* Change connection-default character set in the client. */
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "latin2");
/*
Call mysql_change_user() in order to check that new connection will
have UTF8 character set on the client and on the server.
*/
rc= mysql_change_user(mysql, username, password, (schema) ? schema : "test");
check_mysql_rc(rc, mysql);
/* Retrieve character set information. */
bug30472_retrieve_charset_info(mysql,
character_set_name_4,
character_set_client_4,
character_set_results_4,
collation_connnection_4);
/* Check that we have UTF8 on the server and on the client. */
FAIL_UNLESS(strcmp(character_set_name_4, "latin2") == 0, "cs_name != latin2");
FAIL_UNLESS(strcmp(character_set_client_4, "latin2") == 0, "cs_client != latin2");
FAIL_UNLESS(strcmp(character_set_results_4, "latin2") == 0, "cs_result != latin2");
FAIL_UNLESS(strcmp(collation_connnection_4, "latin2_general_ci") == 0,
"collation_connection != latin2_general_ci");
/* That's it. Cleanup. */
return OK;
}
static int test_bug_54100(MYSQL *mysql)
{
MYSQL_RES *result;
MYSQL_ROW row;
int rc;
rc= mysql_query(mysql, "SHOW CHARACTER SET");
check_mysql_rc(rc, mysql);
result= mysql_store_result(mysql);
while ((row= mysql_fetch_row(result)))
{
/* ignore ucs2 */
if (strcmp(row[0], "ucs2")
&& strcmp(row[0], "utf16le")
&& (strcmp(row[0], "utf8mb4") && mariadb_connection(mysql) && mysql_get_server_version(mysql) < 100600)
&& (strcmp(row[0], "utf8") && mariadb_connection(mysql) && mysql_get_server_version(mysql) >= 100600)
&& strcmp(row[0], "utf16")
&& strcmp(row[0], "utf32")) {
rc= mysql_set_character_set(mysql, row[0]);
check_mysql_rc(rc, mysql);
}
}
mysql_free_result(result);
return OK;
}
/* We need this internal function for the test */
static int test_utf16_utf32_noboms(MYSQL *mysql __attribute__((unused)))
{
#ifndef HAVE_ICONV
diag("MariaDB Connector/C was built without iconv support");
return SKIP;
#else
const char *csname[]= {"utf16", "utf16le", "utf32", "utf8"};
MARIADB_CHARSET_INFO *csinfo[sizeof(csname)/sizeof(char*)];
const int UTF8= sizeof(csname)/sizeof(char*) - 1;
unsigned char in_string[][8]= {"\xd8\x02\xdc\x60\0", /* utf16(be) */
"\x02\xd8\x60\xdc\0", /* utf16le */
"\x00\x01\x08\x60\0\0\0", /* utf32(be) */
"\xF0\x90\xA1\xA0" }; /* utf8 */
size_t in_oct_len[]= {6, 6, 8, 5};
char buffer[8], as_hex[16];
int i, error;
size_t rc, in_len, out_len;
for (i= 0; i < (int)(sizeof(csname)/sizeof(char*)); ++i)
{
csinfo[i]= mariadb_get_charset_by_name(csname[i]);
if (csinfo[i] == NULL)
{
diag("Could not get cs info for %s", csname[i]);
return FAIL;
}
}
for (i= 0; i < UTF8; ++i)
{
in_len= in_oct_len[i];
out_len= sizeof(buffer);
diag("Converting %s->%s", csname[i], csname[UTF8]);
rc= mariadb_convert_string((char *)in_string[i], &in_len, csinfo[i], buffer, &out_len, csinfo[UTF8], &error);
FAIL_IF(rc == (size_t)-1, "Conversion failed");
FAIL_IF(rc != in_oct_len[UTF8], "Incorrect number of written bytes");
if (memcmp(buffer, in_string[UTF8], rc) != 0)
{
mysql_hex_string(as_hex, buffer, (unsigned long)rc);
diag("Converted string(%s) does not match the expected one", as_hex);
return FAIL;
}
in_len= in_oct_len[UTF8];
out_len= sizeof(buffer);
diag("Converting %s->%s", csname[UTF8], csname[i]);
rc= mariadb_convert_string((char *)in_string[UTF8], &in_len, csinfo[UTF8], buffer, &out_len, csinfo[i], &error);
FAIL_IF(rc == (size_t)-1, "Conversion failed");
diag("rc=%lu oct_len: %lu", (unsigned long)rc, (unsigned long)in_oct_len[i]);
FAIL_IF(rc != in_oct_len[i], "Incorrect number of written bytes");
if (memcmp(buffer, in_string[i], rc) != 0)
{
mysql_hex_string(as_hex, buffer, (unsigned long)rc);
diag("Converted string(%s) does not match the expected one", as_hex);
return FAIL;
}
}
return OK;
#endif
}
static int charset_auto(MYSQL *my __attribute__((unused)))
{
const char *csname1, *csname2;
const char *osname;
MYSQL *mysql= mysql_init(NULL);
int rc;
osname= madb_get_os_character_set();
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "auto");
FAIL_IF(!my_test_connect(mysql, hostname, username,
password, schema, port, socketname, 0),
mysql_error(mysql));
csname1= mysql_character_set_name(mysql);
diag("Character set: %s os charset: %s", csname1, osname);
FAIL_IF(!strcasecmp(osname,"utf8") ? strncmp(osname, csname1, 4) :
strcmp(osname, csname1),
"character set is not os character set");
if (strcmp(osname, "utf8"))
{
rc= mysql_set_character_set(mysql, "utf8");
check_mysql_rc(rc, mysql);
csname2= mysql_character_set_name(mysql);
diag("Character set: %s", csname2);
FAIL_IF(!strcmp(csname2, csname1), "Wrong charset: expected utf8");
rc= mysql_set_character_set(mysql, "auto");
check_mysql_rc(rc, mysql);
csname2= mysql_character_set_name(mysql);
diag("Character set: %s", csname2);
FAIL_IF(strcmp(csname2, osname), "Wrong charset: expected os charset");
}
mysql_close(mysql);
return OK;
}
/* check if all server character sets are supported */
static int test_conc223(MYSQL *mysql)
{
int rc;
MYSQL_RES *res;
MYSQL_ROW row;
int found= 0;
SKIP_MYSQL(mysql);
rc= mysql_query(mysql, "SELECT ID, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLLATIONS");
check_mysql_rc(rc, mysql);
res= mysql_store_result(mysql);
while ((row = mysql_fetch_row(res)))
{
int id= atoi(row[0]);
if (!mariadb_get_charset_by_nr(id))
{
diag("%04d %s %s", id, row[1], row[2]);
found++;
}
}
mysql_free_result(res);
if (found)
{
diag("%d character sets/collations not found", found);
return FAIL;
}
return OK;
}
struct my_tests_st my_tests[] = {
{"test_conc223", test_conc223, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"charset_auto", charset_auto, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"bug_8378: mysql_real_escape with gbk", bug_8378, TEST_CONNECTION_NEW, 0, opt_bug8378, NULL},
{"test_client_character_set", test_client_character_set, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"bug_10214: mysql_real_escape with NO_BACKSLASH_ESCAPES", bug_10214, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_escaping", test_escaping, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conversion", test_conversion, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"bug_41785", bug_41785, TEST_CONNECTION_DEFAULT, 0, NULL, "not fixed yet"},
{"test_bug27876", test_bug27876, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_bug30472", test_bug30472, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"test_ps_i18n", test_ps_i18n, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_bug_54100", test_bug_54100, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"test_utf16_utf32_noboms", test_utf16_utf32_noboms, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, 0}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

View File

@ -0,0 +1,53 @@
#include "my_test.h"
#define MAX_COUNT 2000
int main(int argc, char *argv[]) {
MYSQL *mysql;
int i;
if (argc > 1)
get_options(argc, argv);
get_envvars();
if (IS_SKYSQL(hostname))
return 0;
diag("hostname: %s", hostname);
for (i = 0; i < MAX_COUNT; ++i) {
if (mysql_library_init(-1, NULL, NULL) != 0) {
diag("mysql_library_init failed");
return 1;
}
mysql = mysql_init(NULL);
if (!mysql) {
diag("mysql_init failed");
return 1;
}
if (force_tls)
mysql_options(mysql, MYSQL_OPT_SSL_ENFORCE, &force_tls);
if (!mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0)) {
diag("mysql_real_connect failed: %s", mysql_error(mysql));
return 1;
}
if (mysql_query(mysql, "SELECT NULL LIMIT 0") != 0) {
diag("mysql_query failed: %s", mysql_error(mysql));
return 1;
}
mysql_close(mysql);
mysql_library_end();
}
return 0;
}

File diff suppressed because it is too large Load Diff

1841
vendor/MDBC/unittest/libmariadb/cursor.c vendored Normal file

File diff suppressed because it is too large Load Diff

100
vendor/MDBC/unittest/libmariadb/data.csv vendored Normal file
View File

@ -0,0 +1,100 @@
00000100,1,60000.000000
00000101,2,60000.000000
00000102,3,60000.000000
00000103,1,60000.000000
00000104,2,60000.000000
00000105,3,60000.000000
00000106,1,60000.000000
00000107,2,60000.000000
00000108,3,60000.000000
00000109,1,60000.000000
00000110,2,60000.000000
00000111,3,60000.000000
00000112,1,60000.000000
00000113,2,60000.000000
00000114,3,60000.000000
00000115,1,60000.000000
00000116,2,60000.000000
00000117,3,60000.000000
00000118,1,60000.000000
00000119,2,60000.000000
00000120,3,60000.000000
00000121,1,60000.000000
00000122,2,60000.000000
00000123,3,60000.000000
00000124,1,60000.000000
00000125,2,60000.000000
00000126,3,60000.000000
00000127,1,60000.000000
00000128,2,60000.000000
00000129,3,60000.000000
00000130,1,60000.000000
00000131,2,60000.000000
00000132,3,60000.000000
00000133,1,60000.000000
00000134,2,60000.000000
00000135,3,60000.000000
00000136,1,60000.000000
00000137,2,60000.000000
00000138,3,60000.000000
00000139,1,60000.000000
00000140,2,60000.000000
00000141,3,60000.000000
00000142,1,60000.000000
00000143,2,60000.000000
00000144,3,60000.000000
00000145,1,60000.000000
00000146,2,60000.000000
00000147,3,60000.000000
00000148,1,60000.000000
00000149,2,60000.000000
00000150,3,60000.000000
00000151,1,60000.000000
00000152,2,60000.000000
00000153,3,60000.000000
00000154,1,60000.000000
00000155,2,60000.000000
00000156,3,60000.000000
00000157,1,60000.000000
00000158,2,60000.000000
00000159,3,60000.000000
00000160,1,60000.000000
00000161,2,60000.000000
00000162,3,60000.000000
00000163,1,60000.000000
00000164,2,60000.000000
00000165,3,60000.000000
00000166,1,60000.000000
00000167,2,60000.000000
00000168,3,60000.000000
00000169,1,60000.000000
00000170,2,60000.000000
00000171,3,60000.000000
00000172,1,60000.000000
00000173,2,60000.000000
00000174,3,60000.000000
00000175,1,60000.000000
00000176,2,60000.000000
00000177,3,60000.000000
00000178,1,60000.000000
00000179,2,60000.000000
00000180,3,60000.000000
00000181,1,60000.000000
00000182,2,60000.000000
00000183,3,60000.000000
00000184,1,60000.000000
00000185,2,60000.000000
00000186,3,60000.000000
00000187,1,60000.000000
00000188,2,60000.000000
00000189,3,60000.000000
00000190,1,60000.000000
00000191,2,60000.000000
00000192,3,60000.000000
00000193,1,60000.000000
00000194,2,60000.000000
00000195,3,60000.000000
00000196,1,60000.000000
00000197,2,60000.000000
00000198,3,60000.000000
00000199,1,60000.000000
1 00000100 1 60000.000000
2 00000101 2 60000.000000
3 00000102 3 60000.000000
4 00000103 1 60000.000000
5 00000104 2 60000.000000
6 00000105 3 60000.000000
7 00000106 1 60000.000000
8 00000107 2 60000.000000
9 00000108 3 60000.000000
10 00000109 1 60000.000000
11 00000110 2 60000.000000
12 00000111 3 60000.000000
13 00000112 1 60000.000000
14 00000113 2 60000.000000
15 00000114 3 60000.000000
16 00000115 1 60000.000000
17 00000116 2 60000.000000
18 00000117 3 60000.000000
19 00000118 1 60000.000000
20 00000119 2 60000.000000
21 00000120 3 60000.000000
22 00000121 1 60000.000000
23 00000122 2 60000.000000
24 00000123 3 60000.000000
25 00000124 1 60000.000000
26 00000125 2 60000.000000
27 00000126 3 60000.000000
28 00000127 1 60000.000000
29 00000128 2 60000.000000
30 00000129 3 60000.000000
31 00000130 1 60000.000000
32 00000131 2 60000.000000
33 00000132 3 60000.000000
34 00000133 1 60000.000000
35 00000134 2 60000.000000
36 00000135 3 60000.000000
37 00000136 1 60000.000000
38 00000137 2 60000.000000
39 00000138 3 60000.000000
40 00000139 1 60000.000000
41 00000140 2 60000.000000
42 00000141 3 60000.000000
43 00000142 1 60000.000000
44 00000143 2 60000.000000
45 00000144 3 60000.000000
46 00000145 1 60000.000000
47 00000146 2 60000.000000
48 00000147 3 60000.000000
49 00000148 1 60000.000000
50 00000149 2 60000.000000
51 00000150 3 60000.000000
52 00000151 1 60000.000000
53 00000152 2 60000.000000
54 00000153 3 60000.000000
55 00000154 1 60000.000000
56 00000155 2 60000.000000
57 00000156 3 60000.000000
58 00000157 1 60000.000000
59 00000158 2 60000.000000
60 00000159 3 60000.000000
61 00000160 1 60000.000000
62 00000161 2 60000.000000
63 00000162 3 60000.000000
64 00000163 1 60000.000000
65 00000164 2 60000.000000
66 00000165 3 60000.000000
67 00000166 1 60000.000000
68 00000167 2 60000.000000
69 00000168 3 60000.000000
70 00000169 1 60000.000000
71 00000170 2 60000.000000
72 00000171 3 60000.000000
73 00000172 1 60000.000000
74 00000173 2 60000.000000
75 00000174 3 60000.000000
76 00000175 1 60000.000000
77 00000176 2 60000.000000
78 00000177 3 60000.000000
79 00000178 1 60000.000000
80 00000179 2 60000.000000
81 00000180 3 60000.000000
82 00000181 1 60000.000000
83 00000182 2 60000.000000
84 00000183 3 60000.000000
85 00000184 1 60000.000000
86 00000185 2 60000.000000
87 00000186 3 60000.000000
88 00000187 1 60000.000000
89 00000188 2 60000.000000
90 00000189 3 60000.000000
91 00000190 1 60000.000000
92 00000191 2 60000.000000
93 00000192 3 60000.000000
94 00000193 1 60000.000000
95 00000194 2 60000.000000
96 00000195 3 60000.000000
97 00000196 1 60000.000000
98 00000197 2 60000.000000
99 00000198 3 60000.000000
100 00000199 1 60000.000000

323
vendor/MDBC/unittest/libmariadb/dyncol.c vendored Normal file
View File

@ -0,0 +1,323 @@
/*
Copyright (c) 2013 Monty Program AB. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "my_test.h"
#include "mariadb_dyncol.h"
static int create_dyncol_named(MYSQL *mysql)
{
DYNAMIC_COLUMN dyncol;
DYNAMIC_COLUMN_VALUE *vals;
uint i, column_count= 6;
int rc;
const char *strval[]= {"Val1", "Val2", "Val3", "Val4", "Val5", "Val6"};
MYSQL_LEX_STRING keys1[]= {{(char *)"key1", 4}, {(char *)"key2", 4},
{(char *)"key3", 4}, {(char *)"key4", 4},
{(char *)"key5", 4}, {(char *)"key6", 4}},
keys2[]= {{(char *)"key1", 4}, {(char *)"key1", 4},
{(char *)"key3", 4}, {(char *)"key4", 4},
{(char *)"key5", 4}, {(char *)"key6", 4}},
keys3[]= {{(char *)"\x70\x61\x72\x61\x00\x30", 6},
{(char *)"\x70\x61\x72\x61\x00\x31", 6},
{(char *)"\x70\x61\x72\x61\x00\x32", 6},
{(char *)"\x70\x61\x72\x61\x00\x33", 6},
{(char *)"\x70\x61\x72\x61\x00\x34", 6},
{(char *)"\x70\x61\x72\x61\x00\x35", 6}};
MYSQL_LEX_STRING *my_keys;
uint my_count;
vals= (DYNAMIC_COLUMN_VALUE *)malloc(column_count * sizeof(DYNAMIC_COLUMN_VALUE));
for (i=0; i < column_count; i++)
{
vals[i].type= DYN_COL_STRING;
vals[i].x.string.value.str= (char *)strval[i];
vals[i].x.string.value.length= strlen(strval[i]);
vals[i].x.string.charset= (MARIADB_CHARSET_INFO *)mysql->charset;
diag("%s", keys3[i].str);
}
mariadb_dyncol_init(&dyncol);
rc= mariadb_dyncol_create_many_named(&dyncol, column_count, keys1, vals, 0);
mariadb_dyncol_free(&dyncol);
FAIL_IF(mariadb_dyncol_create_many_named(&dyncol, column_count, keys1, vals, 1) < 0, "Error");
column_count= 0;
FAIL_IF(mariadb_dyncol_column_count(&dyncol, &column_count) < 0, "Error");
FAIL_IF(column_count != 6, "6 columns expected");
mariadb_dyncol_free(&dyncol);
rc= mariadb_dyncol_create_many_named(&dyncol, column_count, keys3, vals, 1);
if (rc < 0) {
diag("Error!!: %d", rc);
return FAIL;
}
column_count= 0;
FAIL_IF(mariadb_dyncol_column_count(&dyncol, &column_count) < 0, "Error");
FAIL_IF(column_count != 6, "6 columns expected");
mariadb_dyncol_free(&dyncol);
/* Now try to add a duplicate key */
FAIL_IF(mariadb_dyncol_create_many_named(&dyncol, column_count, keys2, vals, 1) >=0, "Error expected");
mariadb_dyncol_free(&dyncol);
/* binary keys */
rc= mariadb_dyncol_create_many_named(&dyncol, column_count, keys3, vals, 1);
FAIL_IF(rc < 0, "binary keys failed");
/* get keys*/
rc= mariadb_dyncol_list_named(&dyncol, &my_count, &my_keys);
FAIL_IF(rc < 0, "list named failed");
for (i=0; i < my_count; i++)
{
if (memcmp(my_keys[i].str, keys3[i].str, keys3[i].length) != 0)
diag("error key %d", i);
vals[i].type=DYN_COL_NULL;
}
rc= mariadb_dyncol_update_many_named(&dyncol, column_count, keys3, vals);
FAIL_IF(rc < 0, "update failed");
mariadb_dyncol_free(&dyncol);
keys3[0].str= (char *)"test";
for (i=0; i < column_count; i++)
diag("%s", my_keys[i].str);
free(vals);
free(my_keys);
return OK;
}
static int mdev_4994(MYSQL *unused __attribute__((unused)))
{
DYNAMIC_COLUMN dyncol;
uint key= 1;
DYNAMIC_COLUMN_VALUE val;
int rc;
val.type= DYN_COL_NULL;
mariadb_dyncol_init(&dyncol);
rc= mariadb_dyncol_create_many_num(&dyncol, 1, &key, &val, 0);
FAIL_IF(rc < 0, "Unexpected error");
mariadb_dyncol_free(&dyncol);
return OK;
}
static int create_dyncol_num(MYSQL *mysql)
{
DYNAMIC_COLUMN dyncol;
DYNAMIC_COLUMN_VALUE vals[5];
uint i, column_count= 5;
uint my_count;
MYSQL_LEX_STRING *my_keys;
DYNAMIC_COLUMN_VALUE *my_vals;
int rc;
const char *strval[]= {"Val1", "Val2", "Val3", "Val4", "Val5"};
uint keys1[5]= {1,2,3,4,5},
keys2[5]= {1,2,2,4,5};
MYSQL_LEX_STRING key1= {(char *)"1",1};
for (i=0; i < column_count; i++)
{
vals[i].type= DYN_COL_STRING;
vals[i].x.string.value.str= (char *)strval[i];
vals[i].x.string.value.length= strlen(strval[i]);
vals[i].x.string.charset= (MARIADB_CHARSET_INFO *)mysql->charset;
}
FAIL_IF(mariadb_dyncol_create_many_num(&dyncol, column_count, keys1, vals, 1) <0, "Error (keys1)");
vals[0].x.string.value.str= (char *)strval[1];
rc= mariadb_dyncol_update_many_named(&dyncol,1, &key1, vals);
diag("update: %d", rc);
rc= mariadb_dyncol_unpack(&dyncol, &my_count, &my_keys, &my_vals);
diag("unpack: %d %d", rc, my_count);
free(my_keys);
free(my_vals);
FAIL_IF(mariadb_dyncol_column_count(&dyncol, &column_count) < 0, "Error");
FAIL_IF(column_count != 5, "5 columns expected");
mariadb_dyncol_free(&dyncol);
FAIL_IF(mariadb_dyncol_create_many_num(&dyncol, column_count, keys2, vals, 1) >=0, "Error expected (keys2)");
mariadb_dyncol_free(&dyncol);
return OK;
}
static int mdev_x1(MYSQL *mysql)
{
int rc;
uint i;
uint num_keys[5]= {1,2,3,4,5};
const char *strval[]= {"Val1", "Val2", "Val3", "Val4", "Val5"};
DYNAMIC_COLUMN_VALUE vals[5];
DYNAMIC_COLUMN dynstr;
MYSQL_LEX_STRING my_key= {(char *)"1", 2};
uint unpack_columns;
MYSQL_LEX_STRING *unpack_keys;
DYNAMIC_COLUMN_VALUE *unpack_vals;
for (i=0; i < 5; i++)
{
vals[i].type= DYN_COL_STRING;
vals[i].x.string.value.str= (char *)strval[i];
vals[i].x.string.value.length= strlen(strval[i]);
vals[i].x.string.charset= (MARIADB_CHARSET_INFO *)mysql->charset;
}
mariadb_dyncol_init(&dynstr);
/* create numeric */
rc= mariadb_dyncol_create_many_num(&dynstr, 5, num_keys, vals, 1);
if (rc < 0)
{
diag("Error: %d", rc);
return FAIL;
}
/* unpack and print values */
rc= mariadb_dyncol_unpack(&dynstr, &unpack_columns, &unpack_keys, &unpack_vals);
if (rc < 0)
{
diag("Error: %d", rc);
return FAIL;
}
for (i=0; i < unpack_columns; i++)
if (memcmp(unpack_vals[i].x.string.value.str, vals[i].x.string.value.str, vals[i].x.string.value.length))
diag("Error1: key: %1s val: %s %s", unpack_keys[i].str, unpack_vals[i].x.string.value.str, vals[i].x.string.value.str);
free(unpack_keys);
free(unpack_vals);
/* change one value and update with named key */
/* vals[0].x.string.value.str= strval[1]; */
rc= mariadb_dyncol_update_many_named(&dynstr, 1, &my_key, vals);
if (rc < 0)
{
diag("Error: %d", rc);
return FAIL;
}
/* unpack and print values */
rc= mariadb_dyncol_unpack(&dynstr, &unpack_columns, &unpack_keys, &unpack_vals);
if (rc < 0)
{
diag("Error: %d", rc);
return FAIL;
}
diag("Columns: %d", unpack_columns);
for (i=0; i < unpack_columns; i++)
diag("Key: %s Len: %lu", unpack_keys[i].str, (unsigned long)unpack_keys[i].length);
free(unpack_keys);
free(unpack_vals);
mariadb_dyncol_free(&dynstr);
return OK;
}
static int dyncol_column_count(MYSQL *unused __attribute__((unused)))
{
DYNAMIC_COLUMN dyncol;
uint column_count= 5;
int rc;
mariadb_dyncol_init(&dyncol); /* memset(&dyncol, 0, sizeof(DYNAMIC_COLUMN)) */
rc= mariadb_dyncol_column_count(&dyncol, &column_count);
diag("rc=%d", rc);
FAIL_IF(rc < 0, "unexpected error");
FAIL_IF(column_count > 0, "Expected column_count=0");
return OK;
}
static int dyncol_nested(MYSQL *mysql __attribute__((unused)))
{
DYNAMIC_COLUMN col1, col2;
DYNAMIC_COLUMN_VALUE value[2];
MYSQL_LEX_STRING cols[2]= {{(char *)"0",1},{(char *)"1",1}};
DYNAMIC_STRING s;
mariadb_dyncol_init(&col1);
mariadb_dyncol_init(&col2);
memset(&value, 0, sizeof(DYNAMIC_COLUMN_VALUE));
value[0].type= DYN_COL_UINT;
value[0].x.ulong_value = 17;
mariadb_dyncol_create_many_named(&col1, 1, cols, value, 0);
if (mariadb_dyncol_check(&col1) != ER_DYNCOL_OK)
{
diag("Error while creating col1");
return FAIL;
}
value[1].type= DYN_COL_DYNCOL;
value[1].x.string.value.str= col1.str;
value[1].x.string.value.length= col1.length;
mariadb_dyncol_create_many_named(&col2, 2, cols, value, 0);
if (mariadb_dyncol_check(&col2) != ER_DYNCOL_OK)
{
diag("Error while creating col1");
return FAIL;
}
mariadb_dyncol_json(&col2, &s);
if (strcmp(s.str, "{\"0\":17,\"1\":{\"0\":17}}") != 0)
{
diag("%s != %s", s.str, "{\"0\":17,\"1\":{\"0\":17}}");
return FAIL;
}
ma_dynstr_free(&s);
mariadb_dyncol_free(&col1);
mariadb_dyncol_free(&col2);
return OK;
}
struct my_tests_st my_tests[] = {
{"mdev_x1", mdev_x1, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"mdev_4994", mdev_4994, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"create_dyncol_named", create_dyncol_named, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"create_dyncol_num", create_dyncol_num, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"dyncol_column_count", dyncol_column_count, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"dyncol_nested", dyncol_nested, TEST_CONNECTION_NEW, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, 0}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

290
vendor/MDBC/unittest/libmariadb/errors.c vendored Normal file
View File

@ -0,0 +1,290 @@
/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "my_test.h"
/* Test warnings */
static int test_client_warnings(MYSQL *mysql)
{
int rc;
rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
check_mysql_rc(rc, mysql);
FAIL_IF(!mysql_warning_count(mysql), "Warning expected");
return OK;
}
static int test_ps_client_warnings(MYSQL *mysql)
{
int rc;
MYSQL_STMT *stmt;
const char *query= "DROP TABLE IF EXISTS test_non_exists";
rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, SL(query));
FAIL_IF(rc, mysql_stmt_error(stmt));
rc= mysql_stmt_execute(stmt);
FAIL_IF(rc, mysql_stmt_error(stmt));
FAIL_IF(!mysql_warning_count(mysql), "Warning expected");
mysql_stmt_close(stmt);
return OK;
}
static int test_server_warnings(MYSQL *mysql)
{
int rc;
MYSQL_RES *result;
rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SHOW WARNINGS");
check_mysql_rc(rc, mysql);
result= mysql_store_result(mysql);
FAIL_IF(!result, mysql_error(mysql));
FAIL_IF(!mysql_num_rows(result), "Empty resultset");
mysql_free_result(result);
return OK;
}
/* Test errors */
static int test_client_errors(MYSQL *mysql)
{
int rc;
rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE test_non_exists");
FAIL_IF(!rc, "Error expected");
FAIL_IF(!mysql_errno(mysql), "Error expected");
FAIL_IF(!strlen(mysql_error(mysql)), "Empty errormsg");
FAIL_IF(strcmp(mysql_sqlstate(mysql), "00000") == 0, "Invalid SQLstate");
return OK;
}
static int test_ps_client_errors(MYSQL *mysql)
{
int rc;
MYSQL_STMT *stmt;
const char *query= "DROP TABLE test_non_exists";
rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, SL(query));
FAIL_IF(rc, mysql_stmt_error(stmt));
rc= mysql_stmt_execute(stmt);
FAIL_IF(!rc, mysql_stmt_error(stmt));
FAIL_IF(!mysql_stmt_errno(stmt), "Error expected");
FAIL_IF(!strlen(mysql_stmt_error(stmt)), "Empty errormsg");
FAIL_IF(strcmp(mysql_stmt_sqlstate(stmt), "00000") == 0, "Invalid SQLstate");
mysql_stmt_close(stmt);
return OK;
}
static int test_server_errors(MYSQL *mysql)
{
int rc;
MYSQL_RES *result;
rc= mysql_query(mysql, "DROP TABLE if exists test_non_exists");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE test_non_exists");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SHOW ERRORS");
check_mysql_rc(rc, mysql);
result= mysql_store_result(mysql);
FAIL_IF(!result, mysql_error(mysql));
FAIL_IF(!mysql_num_rows(result), "Empty resultset");
mysql_free_result(result);
return OK;
}
/* Bug #16143: mysql_stmt_sqlstate returns an empty string instead of '00000' */
static int test_bug16143(MYSQL *mysql)
{
MYSQL_STMT *stmt;
stmt= mysql_stmt_init(mysql);
FAIL_IF(!stmt, mysql_error(mysql));
/* Check mysql_stmt_sqlstate return "no error" */
FAIL_UNLESS(strcmp(mysql_stmt_sqlstate(stmt), "00000") == 0, "Expected SQLstate 000000");
mysql_stmt_close(stmt);
return OK;
}
/* Test warnings for cuted rows */
static int test_cuted_rows(MYSQL *mysql)
{
int rc, count;
MYSQL_RES *result;
if (!is_mariadb)
return SKIP;
rc= mysql_query(mysql, "DROP TABLE if exists t1");
check_mysql_rc(rc, mysql);
mysql_query(mysql, "DROP TABLE if exists t2");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1(c1 tinyint)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t2(c1 int not null)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "FLUSH TABLES");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "START TRANSACTION");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t1 values(10), (NULL), (NULL)");
check_mysql_rc(rc, mysql);
count= mysql_warning_count(mysql);
FAIL_UNLESS(count == 0, "warnings != 0");
rc= mysql_query(mysql, "INSERT INTO t2 SELECT * FROM t1");
check_mysql_rc(rc, mysql);
count= mysql_warning_count(mysql);
FAIL_UNLESS(count == 2, "warnings != 2");
rc= mysql_query(mysql, "SHOW WARNINGS");
check_mysql_rc(rc, mysql);
result= mysql_store_result(mysql);
FAIL_IF(!result, "Invalid result set");
rc= 0;
while (mysql_fetch_row(result))
rc++;
FAIL_UNLESS(rc == 2, "rowcount != 2");
mysql_free_result(result);
rc= mysql_query(mysql, "INSERT INTO t1 VALUES('junk'), (876789)");
check_mysql_rc(rc, mysql);
count= mysql_warning_count(mysql);
FAIL_UNLESS(count == 2, "warnings != 2");
rc= mysql_query(mysql, "SHOW WARNINGS");
check_mysql_rc(rc, mysql);
result= mysql_store_result(mysql);
FAIL_IF(!result, "Invalid result set");
rc= 0;
while (mysql_fetch_row(result))
rc++;
FAIL_UNLESS(rc == 2, "rowcount != 2");
mysql_free_result(result);
rc= mysql_query(mysql, "DROP TABLE t1, t2");
check_mysql_rc(rc, mysql);
return OK;
}
static int test_parse_error_and_bad_length(MYSQL *mysql)
{
MYSQL_STMT *stmt;
int rc;
char stmt_str[128];
/* check that we get 4 syntax errors over the 4 calls */
rc= mysql_query(mysql, "SHOW DATABAAAA");
FAIL_UNLESS(rc, "Error expected");
rc= mysql_real_query(mysql, SL_BIN("SHOW DATABASES\0AAA"));
FAIL_UNLESS(rc, "Error expected");
stmt= mysql_stmt_init(mysql);
FAIL_IF(!stmt, mysql_error(mysql));
rc= mysql_stmt_prepare(stmt, SL("SHOW DATABAAAA"));
FAIL_IF(!rc, "Error expected");
mysql_stmt_close(stmt);
stmt= mysql_stmt_init(mysql);
FAIL_UNLESS(stmt, "");
memset(stmt_str, 0, 100);
strcpy(stmt_str, "SHOW DATABASES");
rc= mysql_stmt_prepare(stmt, stmt_str, 99);
FAIL_IF(!rc, "Error expected");
mysql_stmt_close(stmt);
return OK;
}
struct my_tests_st my_tests[] = {
{"test_client_warnings", test_client_warnings, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_ps_client_warnings", test_ps_client_warnings, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_server_warnings", test_server_warnings, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_client_errors", test_client_errors, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_ps_client_errors", test_ps_client_errors, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_server_errors", test_server_errors, TEST_CONNECTION_DEFAULT, 0, NULL , "Open bug: #42364"},
{"test_bug16143", test_bug16143, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_cuted_rows", test_cuted_rows, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_parse_error_and_bad_length", test_parse_error_and_bad_length, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

View File

@ -0,0 +1,249 @@
/*
*/
#include "my_test.h"
static int execute_direct(MYSQL *mysql)
{
int rc= 0;
long i= 0;
MYSQL_STMT *stmt;
MYSQL_BIND bind;
unsigned int param_count= 1;
MYSQL_RES *res= NULL;
stmt= mysql_stmt_init(mysql);
rc= mariadb_stmt_execute_direct(stmt, "DROP TABLE IF EXISTS t1", -1);
check_stmt_rc(rc, stmt);
rc= mariadb_stmt_execute_direct(stmt, "SELECT 1", -1);
check_stmt_rc(rc, stmt);
while (!mysql_stmt_fetch(stmt));
rc= mariadb_stmt_execute_direct(stmt, "SELECT 1", -1);
check_stmt_rc(rc, stmt);
rc= mariadb_stmt_execute_direct(stmt, "CREATE TABLE t1 (a int)", -1);
check_stmt_rc(rc, stmt);
rc= mysql_query(mysql, "FLUSH TABLES");
check_mysql_rc(rc, mysql);
memset(&bind, 0, sizeof(MYSQL_BIND));
bind.buffer= &i;
bind.buffer_type= MYSQL_TYPE_LONG;
bind.buffer_length= sizeof(long);
mysql_stmt_close(stmt);
stmt= mysql_stmt_init(mysql);
mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &param_count);
rc= mysql_stmt_bind_param(stmt, &bind);
check_stmt_rc(rc, stmt);
rc= mariadb_stmt_execute_direct(stmt, "INSERT INTO t1 VALUES (?)", -1);
check_stmt_rc(rc, stmt);
rc= mysql_query(mysql, "START TRANSACTION");
check_mysql_rc(rc, mysql);
for (i=1; i < 1000; i++)
{
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
}
rc= mysql_stmt_close(stmt);
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SELECT * FROM t1");
check_mysql_rc(rc, mysql);
res= mysql_store_result(mysql);
FAIL_IF(mysql_num_rows(res) != 1000, "Expected 1000 rows");
mysql_free_result(res);
rc= mysql_query(mysql, "COMMIT");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE t1");
check_mysql_rc(rc, mysql);
return OK;
}
static int execute_direct_example(MYSQL *mysql)
{
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
MYSQL_BIND bind[2];
int intval= 1;
int param_count= 2;
int rc;
const char *strval= "execute_direct_example1";
/* Direct execution without parameters */
rc= mariadb_stmt_execute_direct(stmt, "DROP TABLE IF EXISTS execute_direct", -1);
check_stmt_rc(rc, stmt);
rc= mariadb_stmt_execute_direct(stmt, "CREATE TABLE execute_direct (a int, b varchar(20))", -1);
rc= mysql_stmt_close(stmt);
stmt= mysql_stmt_init(mysql);
check_stmt_rc(rc, stmt);
memset(bind, 0, sizeof(MYSQL_BIND) * 2);
bind[0].buffer_type= MYSQL_TYPE_SHORT;
bind[0].buffer= &intval;
bind[1].buffer_type= MYSQL_TYPE_STRING;
bind[1].buffer= (char *)strval;
bind[1].buffer_length= (unsigned long)strlen(strval);
/* set number of parameters */
rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &param_count);
check_stmt_rc(rc, stmt);
/* bind parameters */
rc= mysql_stmt_bind_param(stmt, bind);
check_stmt_rc(rc, stmt);
rc= mariadb_stmt_execute_direct(stmt, "INSERT INTO execute_direct VALUES (?,?)", -1);
check_stmt_rc(rc, stmt);
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP TABLE execute_direct");
check_mysql_rc(rc, mysql);
return OK;
}
static int conc_213(MYSQL *mysql)
{
MYSQL_BIND bind;
unsigned int param_count= 1;
long id= 1234;
MYSQL_STMT *stmt;
stmt = mysql_stmt_init(mysql);
memset(&bind, '\0', sizeof(bind));
bind.buffer_type = MYSQL_TYPE_LONG;
bind.buffer = (void *)&id;
bind.buffer_length = sizeof(long);
/* bind.is_null = &is_null;
bind.length = &length;
bind.error = &error; */
mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &param_count);
check_stmt_rc(mysql_stmt_bind_param(stmt, &bind), stmt);
check_stmt_rc(mariadb_stmt_execute_direct(stmt, "SELECT ?", -1), stmt);
check_stmt_rc(mysql_stmt_store_result(stmt), stmt);
check_stmt_rc(mysql_stmt_free_result(stmt), stmt);
mysql_stmt_close(stmt);
return OK;
}
static int conc_212(MYSQL *mysql)
{
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
int rc;
rc= mariadb_stmt_execute_direct(stmt, "SELECT 1, 2", -1);
check_stmt_rc(rc, stmt);
mysql_stmt_store_result(stmt);
mysql_stmt_free_result(stmt);
rc= mariadb_stmt_execute_direct(stmt, "SELECT 1, 2", -1);
check_stmt_rc(rc, stmt);
mysql_stmt_store_result(stmt);
mysql_stmt_free_result(stmt);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc,mysql);
rc= mysql_stmt_close(stmt);
return OK;
}
static int conc_218(MYSQL *mysql)
{
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
MYSQL_BIND bind[2];
int id=1;
my_bool is_null= 0, error= 0;
unsigned int param_count= 1;
memset(bind, 0, 2 * sizeof(MYSQL_BIND));
bind[0].buffer_type = MYSQL_TYPE_LONG;
bind[0].buffer = (void *)&id;
bind[0].buffer_length = 4;
bind[0].is_null = &is_null;
bind[0].error = &error;
mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &param_count);
check_stmt_rc(mysql_stmt_bind_param(stmt, bind), stmt);
check_stmt_rc(mariadb_stmt_execute_direct(stmt, "SELECT ?", -1), stmt);
check_stmt_rc(mysql_stmt_store_result(stmt), stmt);
check_stmt_rc(mysql_stmt_free_result(stmt), stmt);
param_count= 1;
mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, &param_count);
check_stmt_rc(mysql_stmt_bind_param(stmt, bind), stmt);
check_stmt_rc(mariadb_stmt_execute_direct(stmt, "SELECT ?", -1), stmt);
mysql_stmt_close(stmt);
return OK;
}
static int test_cursor(MYSQL *mysql)
{
int rc;
MYSQL_STMT *stmt;
unsigned long prefetch_rows= 1;
unsigned long cursor_type= CURSOR_TYPE_READ_ONLY;
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &cursor_type);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, &prefetch_rows);
check_stmt_rc(rc, stmt);
rc= mariadb_stmt_execute_direct(stmt, "SELECT 1 FROM DUAL UNION SELECT 2 FROM DUAL", -1);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
rc= mariadb_stmt_execute_direct(stmt, "SELECT 1 FROM DUAL UNION SELECT 2 FROM DUAL", -1);
check_stmt_rc(rc, stmt);
mysql_stmt_close(stmt);
return OK;
}
struct my_tests_st my_tests[] = {
{"test_cursor", test_cursor, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"conc_218", conc_218, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"conc_212", conc_212, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"conc_213", conc_213, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"execute_direct", execute_direct, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"execute_direct_example", execute_direct_example, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
mysql_library_init(0,0,NULL);
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
mysql_server_end();
return(exit_status());
}

1003
vendor/MDBC/unittest/libmariadb/fetch.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
86DD6D764C0CA47C5014E1E7802674BFDB674ED3
@SSL_CERT_FINGER_PRINT@
73F1FEC1FE041473563BFF2D624B88F6CFCFE626

742
vendor/MDBC/unittest/libmariadb/getopt.c vendored Normal file
View File

@ -0,0 +1,742 @@
/* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
Free Software Foundation, Inc.
Changes by monty:
- Added include of string.h when necessary.
- Removed two warnings from gcc.
This file is part of the GNU C Library. Its master source is NOT part of
the C library, however. The master source lives in /gd/gnu/lib.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */
#ifndef _NO_PROTO
#define _NO_PROTO
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS) && !defined(OS2)
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <ma_global.h> /* Changes for mysys */
#include <ma_string.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
#include <stdlib.h>
#endif /* GNU C library. */
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of ARGV so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable POSIXLY_CORRECT disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
#include "ma_getopt.h"
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = NULL;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* XXX 1003.2 says this must be 1 before any call. */
int optind = 1;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Set to an option character which was unrecognized.
This must be initialized on some systems to avoid linking in the
system's own getopt implementation. */
int optopt = '?';
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
POSIXLY_CORRECT is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIXLY_CORRECT, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Value of POSIXLY_CORRECT environment variable. */
static char *posixly_correct;
#ifdef __GNU_LIBRARY__
/* We want to avoid inclusion of string.h with non-GNU libraries
because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work
in GCC. */
#include <string.h>
#define my_index strchr
#else
/* Avoid depending on library functions or files
whose names are inconsistent. */
static char *
my_index (const char *str, int chr)
{
while (*str)
{
if (*str == chr)
return (char *) str;
str++;
}
return 0;
}
/* If using GCC, we can safely declare strlen this way.
If not using GCC, it is ok not to declare it. */
#ifdef __GNUC__
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
That was relevant to code that was here before. */
#if !defined (__STDC__) || !__STDC__
/* gcc with -traditional declares the built-in strlen to return int,
and has done so at least since version 2.4.5. -- rms. */
extern int strlen (const char *);
#endif /* not __STDC__ */
#endif /* __GNUC__ */
#endif /* not __GNU_LIBRARY__ */
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
static int first_nonopt;
static int last_nonopt;
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
static void
exchange (char **argv)
{
int bottom = first_nonopt;
int middle = last_nonopt;
int top = optind;
char *tem;
/* Exchange the shorter segment with the far end of the longer segment.
That puts the shorter segment into the right place.
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
/* Bottom segment is the short one. */
int len = middle - bottom;
register int i;
/* Swap it with the top part of the top segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
}
else
{
/* Top segment is the short one. */
int len = top - middle;
register int i;
/* Swap it with the bottom part of the bottom segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
}
}
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* Initialize the internal data when the first call is made. */
static const char *
_getopt_initialize (const char *optstring)
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
first_nonopt = last_nonopt = optind = 1;
nextchar = NULL;
posixly_correct = getenv ("POSIXLY_CORRECT");
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
return optstring;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns `EOF'.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.
The elements of ARGV aren't really const, because we permute them.
But we pretend they're const in the prototype to be compatible
with other systems.
LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */
int
_getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only)
{
optarg = NULL;
if (optind == 0)
optstring = _getopt_initialize (optstring);
if (nextchar == NULL || *nextchar == '\0')
{
/* Advance to the next ARGV-element. */
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (last_nonopt != optind)
first_nonopt = optind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
&& (argv[optind][0] != '-' || argv[optind][1] == '\0'))
optind++;
last_nonopt = optind;
}
/* The special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return EOF;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Skip the initial punctuation. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
/* Decode the current option-ARGV-element. */
/* Check whether the ARGV-element is a long option.
If long_only and the ARGV-element has the form "-f", where f is
a valid short option, don't consider it an abbreviated form of
a long option that starts with f. Otherwise there would be no
way to give the -f short option.
On the other hand, if there's a long option "fubar" and
the ARGV-element is "-fu", do consider that an abbreviation of
the long option, just like "--fu", and not "-f" with arg "u".
This distinction seems to be the most useful approach. */
if (longopts != NULL
&& (argv[optind][1] == '-'
|| (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound=0; /* Keep gcc happy */
int option_index;
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if ((size_t) (nameend - nextchar) == (size_t) strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, "%s: option `%s' is ambiguous\n",
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (opterr)
{
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
"%s: option `--%s' doesn't allow an argument\n",
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
"%s: option `%c%s' doesn't allow an argument\n",
argv[0], argv[optind - 1][0], pfound->name);
}
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr, "%s: option `%s' requires an argument\n",
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, "%s: unrecognized option `--%s'\n",
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
return '?';
}
}
/* Look at and handle the next short option-character. */
{
char c = *nextchar++;
char *temp = my_index (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*nextchar == '\0')
++optind;
if (temp == NULL || c == ':')
{
if (opterr)
{
if (posixly_correct)
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
else
fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
}
optopt = c;
return '?';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = NULL;
nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
{
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: option requires an argument -- %c\n",
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}
int
getopt (int argc, char *const *argv, const char *optstring)
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}
#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of `getopt'. */
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
if (c == EOF)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

217
vendor/MDBC/unittest/libmariadb/logs.c vendored Normal file
View File

@ -0,0 +1,217 @@
/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "my_test.h"
#ifdef ENABLE_IF_IN_USE
static int enable_general_log(MYSQL *mysql, int truncate)
{
int rc;
rc= mysql_query(mysql, "set @save_global_general_log=@@global.general_log");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "set @@global.general_log=on");
check_mysql_rc(rc, mysql);
if (truncate)
{
rc= mysql_query(mysql, "truncate mysql.general_log");
check_mysql_rc(rc, mysql);
}
return OK;
}
static int restore_general_log(MYSQL *mysql)
{
int rc;
rc= mysql_query(mysql, "set @@global.general_log=@save_global_general_log");
check_mysql_rc(rc, mysql);
return OK;
}
#endif
/* Test update/binary logs */
static int test_logs(MYSQL *mysql)
{
MYSQL_STMT *stmt;
MYSQL_BIND my_bind[2];
char data[255];
size_t length;
int rc;
short id;
rc= mysql_query(mysql, "SET session sql_mode=''");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_logs");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE test_logs(id smallint, name varchar(20))");
check_mysql_rc(rc, mysql);
strcpy((char *)data, "INSERT INTO test_logs VALUES(?, ?)");
stmt= mysql_stmt_init(mysql);
FAIL_IF(!stmt, mysql_error(mysql));
rc= mysql_stmt_prepare(stmt, SL(data));
check_stmt_rc(rc, stmt);
memset(my_bind, '\0', sizeof(my_bind));
my_bind[0].buffer_type= MYSQL_TYPE_SHORT;
my_bind[0].buffer= (void *)&id;
my_bind[1].buffer_type= MYSQL_TYPE_STRING;
my_bind[1].buffer= (void *)&data;
my_bind[1].buffer_length= 255;
my_bind[1].length= (unsigned long *)&length;
id= 9876;
strcpy((char *)data, "MySQL - Open Source Database");
length= strlen(data);
rc= mysql_stmt_bind_param(stmt, my_bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
strcpy((char *)data, "'");
length= 1;
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
strcpy((char *)data, "\"");
length= 1;
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
strcpy((char *)data, "my\'sql\'");
length= strlen(data);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
strcpy((char *)data, "my\"sql\"");
length= strlen(data);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
mysql_stmt_close(stmt);
strcpy((char *)data, "INSERT INTO test_logs VALUES(20, 'mysql')");
stmt= mysql_stmt_init(mysql);
FAIL_IF(!stmt, mysql_error(mysql));
rc= mysql_stmt_prepare(stmt, SL(data));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
mysql_stmt_close(stmt);
strcpy((char *)data, "SELECT * FROM test_logs WHERE id=?");
stmt= mysql_stmt_init(mysql);
FAIL_IF(!stmt, mysql_error(mysql));
rc= mysql_stmt_prepare(stmt, SL(data));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_bind_param(stmt, my_bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
my_bind[1].buffer_length= 255;
rc= mysql_stmt_bind_result(stmt, my_bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
FAIL_UNLESS(id == 9876, "id != 9876");
FAIL_UNLESS(length == 19 || length == 20, "Invalid Length"); /* Due to VARCHAR(20) */
FAIL_UNLESS(strncmp(data, "MySQL - Open Source", 19) == 0, "data != 'MySQL - Open Source'");
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
FAIL_UNLESS(length == 1, "length != 1");
FAIL_UNLESS(strcmp(data, "'") == 0, "data != '''");
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
FAIL_UNLESS(length == 1, "length != 1");
FAIL_UNLESS(strcmp(data, "\"") == 0, "data != '\"'");
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
FAIL_UNLESS(length == 7, "length != 7");
FAIL_UNLESS(strcmp(data, "my\'sql\'") == 0, "data != my'sql'");
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
FAIL_UNLESS(length == 7, "length != 7");
rc= mysql_stmt_fetch(stmt);
FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP TABLE test_logs");
check_mysql_rc(rc, mysql);
return OK;
}
struct my_tests_st my_tests[] = {
{"test_logs", test_logs, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

View File

@ -0,0 +1,741 @@
/* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
Free Software Foundation, Inc.
Changes by monty:
- Added include of string.h when necessary.
- Removed two warnings from gcc.
This file is part of the GNU C Library. Its master source is NOT part of
the C library, however. The master source lives in /gd/gnu/lib.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */
#ifndef _NO_PROTO
#define _NO_PROTO
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS) && !defined(OS2)
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
#include <stdlib.h>
#endif /* GNU C library. */
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of ARGV so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable POSIXLY_CORRECT disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
#include "ma_getopt.h"
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = NULL;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* XXX 1003.2 says this must be 1 before any call. */
int optind = 1;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Set to an option character which was unrecognized.
This must be initialized on some systems to avoid linking in the
system's own getopt implementation. */
int optopt = '?';
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
POSIXLY_CORRECT is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIXLY_CORRECT, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Value of POSIXLY_CORRECT environment variable. */
static char *posixly_correct;
#ifdef __GNU_LIBRARY__
/* We want to avoid inclusion of string.h with non-GNU libraries
because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work
in GCC. */
#include <string.h>
#define my_index strchr
#else
/* Avoid depending on library functions or files
whose names are inconsistent. */
static char *
my_index (const char *str, int chr)
{
while (*str)
{
if (*str == chr)
return (char *) str;
str++;
}
return 0;
}
/* If using GCC, we can safely declare strlen this way.
If not using GCC, it is ok not to declare it. */
#ifdef __GNUC__
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
That was relevant to code that was here before. */
#if !defined (__STDC__) || !__STDC__
/* gcc with -traditional declares the built-in strlen to return int,
and has done so at least since version 2.4.5. -- rms. */
extern int strlen (const char *);
#endif /* not __STDC__ */
#endif /* __GNUC__ */
#endif /* not __GNU_LIBRARY__ */
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
static int first_nonopt;
static int last_nonopt;
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
static void
exchange (char **argv)
{
int bottom = first_nonopt;
int middle = last_nonopt;
int top = optind;
char *tem;
/* Exchange the shorter segment with the far end of the longer segment.
That puts the shorter segment into the right place.
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
/* Bottom segment is the short one. */
int len = middle - bottom;
register int i;
/* Swap it with the top part of the top segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
}
else
{
/* Top segment is the short one. */
int len = top - middle;
register int i;
/* Swap it with the bottom part of the bottom segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
}
}
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* Initialize the internal data when the first call is made. */
static const char *
_getopt_initialize (const char *optstring)
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
first_nonopt = last_nonopt = optind = 1;
nextchar = NULL;
posixly_correct = getenv ("POSIXLY_CORRECT");
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
return optstring;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns `EOF'.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.
The elements of ARGV aren't really const, because we permute them.
But we pretend they're const in the prototype to be compatible
with other systems.
LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */
int
_getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only)
{
optarg = NULL;
if (optind == 0)
optstring = _getopt_initialize (optstring);
if (nextchar == NULL || *nextchar == '\0')
{
/* Advance to the next ARGV-element. */
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (last_nonopt != optind)
first_nonopt = optind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
&& (argv[optind][0] != '-' || argv[optind][1] == '\0'))
optind++;
last_nonopt = optind;
}
/* The special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return EOF;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Skip the initial punctuation. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
/* Decode the current option-ARGV-element. */
/* Check whether the ARGV-element is a long option.
If long_only and the ARGV-element has the form "-f", where f is
a valid short option, don't consider it an abbreviated form of
a long option that starts with f. Otherwise there would be no
way to give the -f short option.
On the other hand, if there's a long option "fubar" and
the ARGV-element is "-fu", do consider that an abbreviation of
the long option, just like "--fu", and not "-f" with arg "u".
This distinction seems to be the most useful approach. */
if (longopts != NULL
&& (argv[optind][1] == '-'
|| (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound=0; /* Keep gcc happy */
int option_index;
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if ((size_t) (nameend - nextchar) == (size_t) strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, "%s: option `%s' is ambiguous\n",
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (opterr)
{
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
"%s: option `--%s' doesn't allow an argument\n",
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
"%s: option `%c%s' doesn't allow an argument\n",
argv[0], argv[optind - 1][0], pfound->name);
}
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr, "%s: option `%s' requires an argument\n",
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, "%s: unrecognized option `--%s'\n",
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
return '?';
}
}
/* Look at and handle the next short option-character. */
{
char c = *nextchar++;
char *temp = my_index (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*nextchar == '\0')
++optind;
if (temp == NULL || c == ':')
{
if (opterr)
{
if (posixly_correct)
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
else
fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
}
optopt = c;
return '?';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = NULL;
nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
{
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: option requires an argument -- %c\n",
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}
int
getopt (int argc, char *const *argv, const char *optstring)
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}
#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of `getopt'. */
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
if (c == EOF)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

View File

@ -0,0 +1,135 @@
/* Declarations for getopt.
Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
This file is part of the GNU C Library. Its master source is NOT part of
the C library, however. The master source lives in /gd/gnu/lib.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if defined (__STDC__) && __STDC__ || defined(__cplusplus)
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if ( defined (__STDC__) && __STDC__ ) || defined(__cplusplus) || defined(MSDOS)
#ifdef __EMX__
int getopt (int, char **, __const__ char *);
#elif defined( __GNU_LIBRARY__)
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt (int argc, char *const *argv, const char *optstring);
#endif /* __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
extern int getopt ();
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* _GETOPT_H */

1666
vendor/MDBC/unittest/libmariadb/misc.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,711 @@
/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <ma_global.h>
#include <ma_sys.h>
#include <mysql.h>
#include <tap.h>
#include "ma_getopt.h"
#include <memory.h>
#include <string.h>
#include <errmsg.h>
#include <stdlib.h>
#include <ma_server_error.h>
#include <mysql/client_plugin.h>
#ifndef WIN32
#include <pthread.h>
#else
#include <io.h>
#endif
#ifndef OK
# define OK 0
#endif
#ifndef FAIL
# define FAIL 1
#endif
#ifndef SKIP
# define SKIP -1
#endif
#ifndef FALSE
# define FALSE 0
#endif
#ifndef TRUE
# define TRUE 1
#endif
#define IS_SKYSQL(a) ((a) && strstr((a), "db.skysql.net"))
#define SKIP_SKYSQL \
if (IS_SKYSQL(hostname)) \
{ \
diag("Not supported by SkySQL"); \
return SKIP; \
}
#ifndef HAVE_SSL
#define SKIP_NOTLS \
{ \
diag("TLS not supported"); \
return SKIP;\
}
#else
#define SKIP_NOTLS
#endif
#define IS_MAXSCALE() (getenv("srv")!=NULL && (strcmp(getenv("srv"), "maxscale") == 0 || strcmp(getenv("srv"), "skysql-ha") == 0))
#define SKIP_MAXSCALE \
if (IS_MAXSCALE()) \
{ \
diag("test disabled with maxscale"); \
return SKIP; \
}
#define SKIP_LOAD_INFILE_DISABLE \
if (!((mysql->server_capabilities & CLIENT_LOCAL_FILES) && \
(mysql->options.client_flag & CLIENT_LOCAL_FILES))) { \
diag("Load local infile not supported"); \
return SKIP; \
}
#define MAX_KEY MAX_INDEXES
#define MAX_KEY_LENGTH_DECIMAL_WIDTH 4 /* strlen("4096") */
#define SL(s) (s), (unsigned long)strlen((s))
#define SL_BIN(s) (s), (unsigned long)sizeof((s))
#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
/* prevent warnings on Win64 by using STMT_LEN instead of strlen */
#define STMT_LEN(A) ((unsigned long)strlen((A)))
#define SKIP_TRAVIS()\
do {\
if (getenv("TRAVIS"))\
{\
diag("Skip test on Travis CI");\
return SKIP;\
}\
}while(0)
#define SKIP_MYSQL(mysql)\
do {\
if (!mariadb_connection(mysql))\
{\
diag("Skip test for non MariaDB server");\
return OK;\
}\
} while(0)
#define check_mysql_rc(rc, mysql) \
do {\
if (rc)\
{\
diag("Error (%d): %s (%d) in %s line %d", rc, mysql_error(mysql), \
mysql_errno(mysql), __FILE__, __LINE__);\
return(FAIL);\
}\
} while(0)
#define check_stmt_rc(rc, stmt) \
do {\
if (rc)\
{\
diag("Error: %s (%s: %d)", mysql_stmt_error(stmt), __FILE__, __LINE__);\
return(FAIL);\
}\
} while(0)
#define FAIL_IF(expr, reason)\
do {\
if (expr)\
{\
diag("Error: %s (%s: %d)", reason, __FILE__, __LINE__);\
return FAIL;\
}\
} while(0)
#define FAIL_UNLESS(expr, reason)\
do {\
if (!(expr))\
{\
diag("Error: %s (%s: %d)", reason, __FILE__, __LINE__);\
return FAIL;\
}\
} while(0)
#define SKIP_CONNECTION_HANDLER \
do {\
if (hostname && strstr(hostname, "://"))\
{\
diag("Test skipped (connection handler)");\
return SKIP;\
}\
} while(0)
/* connection options */
#define TEST_CONNECTION_DEFAULT 1 /* default connection */
#define TEST_CONNECTION_NONE 2 /* tests creates own connection */
#define TEST_CONNECTION_NEW 4 /* create a separate connection */
#define TEST_CONNECTION_DONT_CLOSE 8 /* don't close connection */
struct my_option_st
{
enum mysql_option option;
char *value;
};
struct my_tests_st
{
const char *name;
int (*function)(MYSQL *);
int connection;
ulong connect_flags;
struct my_option_st *options;
const char *skipmsg;
};
MYSQL *my_test_connect(MYSQL *mysql,
const char *host,
const char *user,
const char *passwd,
const char *db,
unsigned int port,
const char *unix_socket,
unsigned long clientflag);
static const char *schema = 0;
static char *hostname = 0;
static char *password = 0;
static unsigned int port = 0;
static unsigned int ssl_port = 0;
static char *socketname = 0;
static char *username = 0;
static int force_tls= 0;
static uchar is_mariadb= 0;
static char *this_host= 0;
static char *plugindir= 0;
static unsigned char travis_test= 0;
/*
static struct my_option test_options[] =
{
{"schema", 'd', "database to use", (uchar **) &schema, (uchar **) &schema,
0, GET_STR, REQUIRED_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", (uchar **) &hostname, (uchar **) &hostname,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"password", 'p',
"Password to use when connecting to server.", (uchar **) &password, (uchar **) &password,
0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Port number to use for connection or 0 for default to, in "
"order of preference, my.cnf, $MYSQL_TCP_PORT, "
#if MYSQL_PORT_DEFAULT == 0
"/etc/services, "
#endif
"built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
(uchar **) &port,
(uchar **) &port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"socket", 'S', "Socket file to use for connection",
(uchar **) &socketname, (uchar **) &socketname, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"user", 'u', "User for login if not current user", (uchar **) &username,
(uchar **) &username, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
*/
#define verify_prepare_field(result,no,name,org_name,type,table,\
org_table,db,length,def) \
do_verify_prepare_field((result),(no),(name),(org_name),(type), \
(table),(org_table),(db),(length),(def), \
__FILE__, __LINE__)
int do_verify_prepare_field(MYSQL_RES *result,
unsigned int no, const char *name,
const char *org_name,
enum enum_field_types type __attribute__((unused)),
const char *table,
const char *org_table, const char *db,
unsigned long length __attribute__((unused)),
const char *def __attribute__((unused)),
const char *file __attribute__((unused)),
int line __attribute__((unused)))
{
MYSQL_FIELD *field;
/* MARIADB_CHARSET_INFO *cs; */
FAIL_IF(!(field= mysql_fetch_field_direct(result, no)), "FAILED to get result");
/* cs= mysql_find_charset_nr(field->charsetnr);
FAIL_UNLESS(cs, "Couldn't get character set"); */
FAIL_UNLESS(strcmp(field->name, name) == 0, "field->name differs");
FAIL_UNLESS(strcmp(field->org_name, org_name) == 0, "field->org_name differs");
/*
if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32)
expected_field_length= UINT_MAX32;
*/
/*
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->char_maxlen == 1)
// FAIL_UNLESS(field->type == type, "field->type differs");
if (table)
FAIL_UNLESS(strcmp(field->table, table) == 0, "field->table differs");
if (org_table)
FAIL_UNLESS(strcmp(field->org_table, org_table) == 0, "field->org_table differs");
if (strcmp(field->db,db))
diag("%s / %s", field->db, db);
FAIL_UNLESS(strcmp(field->db, db) == 0, "field->db differs");
/*
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.
*/
return OK;
}
void get_this_host(MYSQL *mysql)
{
MYSQL_RES *res;
MYSQL_ROW row;
if (mysql_query(mysql, "select substr(current_user(), locate('@', current_user())+1)"))
return;
if ((res= mysql_store_result(mysql)))
{
if ((row= mysql_fetch_row(res)))
this_host= strdup(row[0]);
mysql_free_result(res);
}
}
/* Prepare statement, execute, and process result set for given query */
int my_stmt_result(MYSQL *mysql, const char *buff)
{
MYSQL_STMT *stmt;
int row_count= 0;
int rc;
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, buff, (unsigned long)strlen(buff));
FAIL_IF(rc, mysql_stmt_error(stmt));
rc= mysql_stmt_execute(stmt);
FAIL_IF(rc, mysql_stmt_error(stmt));
while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
row_count++;
mysql_stmt_close(stmt);
return row_count;
}
/*
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument)
{
switch (optid) {
case '?':
case 'I':
my_print_help(test_options);
exit(0);
break;
}
return 0;
}
*/
/* Utility function to verify a particular column data */
int verify_col_data(MYSQL *mysql, const char *table, const char *col,
const char *exp_data)
{
static char query[MAX_TEST_QUERY_LENGTH];
MYSQL_RES *result;
MYSQL_ROW row;
int rc;
if (table && col)
{
sprintf(query, "SELECT %s FROM %s LIMIT 1", col, table);
rc= mysql_query(mysql, query);
check_mysql_rc(rc, mysql);
}
result= mysql_use_result(mysql);
FAIL_IF(!result, "Invalid result set");
if (!(row= mysql_fetch_row(result)) || !row[0]) {
diag("Failed to get the result");
goto error;
}
if(strcmp(row[0], exp_data)) {
diag("Expected %s, got %s", exp_data, row[0]);
goto error;
}
mysql_free_result(result);
return OK;
error:
mysql_free_result(result);
return FAIL;
}
my_bool query_int_variable(MYSQL *con, const char *var_name, int *var_value)
{
MYSQL_RES *rs;
MYSQL_ROW row;
char query_buffer[MAX_TEST_QUERY_LENGTH];
my_bool is_null;
sprintf(query_buffer,
"SELECT %s",
(const char *) var_name);
FAIL_IF(mysql_query(con, query_buffer), "Query failed");
FAIL_UNLESS(rs= mysql_store_result(con), "Invaliid result set");
FAIL_UNLESS(row= mysql_fetch_row(rs), "Nothing to fetch");
is_null= row[0] == NULL;
if (!is_null)
*var_value= atoi(row[0]);
mysql_free_result(rs);
return is_null;
}
static void usage()
{
printf("Execute test with the following options:\n");
printf("-h hostname\n");
printf("-u username\n");
printf("-p password\n");
printf("-d database\n");
printf("-S socketname\n");
printf("-t force use of TLS\n");
printf("-P port number\n");
printf("? displays this help and exits\n");
}
void get_options(int argc, char **argv)
{
int c= 0;
while ((c=getopt(argc,argv, "h:u:p:d:w:P:S:t:?")) >= 0)
{
switch(c) {
case 'h':
hostname= optarg;
break;
case 'u':
username= optarg;
break;
case 'p':
password= optarg;
break;
case 'd':
schema= optarg;
break;
case 'P':
port= atoi(optarg);
ssl_port=port;
break;
case 'S':
socketname= optarg;
break;
case 't':
force_tls= 1;
break;
case '?':
usage();
exit(0);
break;
default:
usage();
BAIL_OUT("Unknown option %c\n", c);
}
}
}
int check_variable(MYSQL *mysql, const char *variable, const char *value)
{
char query[MAX_TEST_QUERY_LENGTH];
MYSQL_RES *result;
MYSQL_ROW row;
sprintf(query, "SELECT %s", variable);
result= mysql_store_result(mysql);
if (!result)
return FAIL;
if ((row = mysql_fetch_row(result)))
if (strcmp(row[0], value) == 0) {
mysql_free_result(result);
return OK;
}
mysql_free_result(result);
return FAIL;
}
/*
* function *test_connect
*
* returns a new connection. This function will be called, if the test doesn't
* use default_connection.
*/
MYSQL *test_connect(struct my_tests_st *test)
{
MYSQL *mysql;
int i= 0, rc;
int timeout= 10;
my_bool truncation_report= 1;
if (!(mysql = mysql_init(NULL))) {
BAIL_OUT("Not enough memory available - mysql_init failed");
}
mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, &truncation_report);
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
if (plugindir)
mysql_options(mysql, MYSQL_PLUGIN_DIR, plugindir);
/* option handling */
if (test && test->options) {
while (test->options[i].option)
{
if (mysql_options(mysql, test->options[i].option, test->options[i].value)) {
diag("Couldn't set option %d. Error (%d) %s", test->options[i].option,
mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
return(NULL);
}
i++;
}
}
if (!(my_test_connect(mysql, hostname, username, password,
schema, port, socketname, (test) ? test->connect_flags:0)))
{
diag("Couldn't establish connection to server %s. Error (%d): %s",
hostname, mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
return(NULL);
}
/* Clear sql_mode when establishing a new connection. */
rc= mysql_query(mysql, "SET sql_mode=''");
if (rc)
{
diag("Error (%d): %s (%d) in %s line %d", rc, mysql_error(mysql),
mysql_errno(mysql), __FILE__, __LINE__);
return(NULL);
}
return(mysql);
}
static int reset_connection(MYSQL *mysql) {
int rc;
if (is_mariadb && !IS_MAXSCALE())
rc= mysql_change_user(mysql, username, password, schema);
else
rc= mysql_reset_connection(mysql);
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SET sql_mode=''");
check_mysql_rc(rc, mysql);
return OK;
}
/*
* function get_envvars((
*
* checks for connection related environment variables
*/
void get_envvars() {
char *envvar;
if (!getenv("MYSQLTEST_VARDIR") &&
!getenv("MARIADB_CC_TEST"))
{
skip_all("Tests skipped.\nFor running unittest suite outside of MariaDB server tests,\nplease specify MARIADB_CC_TEST environment variable.");
exit(0);
}
if (getenv("TRAVIS_JOB_ID"))
travis_test= 1;
if (!hostname && (envvar= getenv("MYSQL_TEST_HOST")))
hostname= envvar;
if (!username)
{
if ((envvar= getenv("MYSQL_TEST_USER")))
username= envvar;
else
username= (char *)"root";
}
if (!password && (envvar= getenv("MYSQL_TEST_PASSWD")))
password= envvar;
if (!schema && (envvar= getenv("MYSQL_TEST_DB")))
schema= envvar;
if (!schema)
schema= "test";
if (!port)
{
if ((envvar= getenv("MYSQL_TEST_PORT")))
port= atoi(envvar);
else if ((envvar= getenv("MASTER_MYPORT")))
port= atoi(envvar);
diag("port: %d", port);
}
if (!ssl_port)
{
if ((envvar= getenv("MYSQL_TEST_SSL_PORT")))
ssl_port= atoi(envvar);
else
ssl_port = port;
diag("ssl_port: %d", ssl_port);
}
if (!force_tls && (envvar= getenv("MYSQL_TEST_TLS")))
force_tls= atoi(envvar);
if (!socketname)
{
if ((envvar= getenv("MYSQL_TEST_SOCKET")))
socketname= envvar;
else if ((envvar= getenv("MASTER_MYSOCK")))
socketname= envvar;
diag("socketname: %s", socketname);
}
if ((envvar= getenv("MYSQL_TEST_PLUGINDIR")))
plugindir= envvar;
}
MYSQL *my_test_connect(MYSQL *mysql,
const char *host,
const char *user,
const char *passwd,
const char *db,
unsigned int port,
const char *unix_socket,
unsigned long clientflag)
{
if (force_tls)
mysql_options(mysql, MYSQL_OPT_SSL_ENFORCE, &force_tls);
if (!mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, clientflag))
{
diag("error: %s", mysql_error(mysql));
return NULL;
}
if (mysql && force_tls && !mysql_get_ssl_cipher(mysql))
{
diag("Error: TLS connection not established");
return NULL;
}
if (!this_host)
get_this_host(mysql);
return mysql;
}
void run_tests(struct my_tests_st *test) {
int i, rc, total=0;
MYSQL *mysql, *mysql_default= NULL; /* default connection */
while (test[total].function)
total++;
plan(total);
if ((mysql_default= test_connect(NULL)))
{
diag("Testing against MySQL Server %s", mysql_get_server_info(mysql_default));
diag("Host: %s", mysql_get_host_info(mysql_default));
diag("Client library: %s", mysql_get_client_info());
is_mariadb= mariadb_connection(mysql_default);
}
else
{
BAIL_OUT("Can't connect to a server. Aborting....");
}
for (i=0; i < total; i++) {
if (!mysql_default && (test[i].connection & TEST_CONNECTION_DEFAULT))
{
diag("MySQL server not running");
skip(1, "%s", test[i].name);
} else if (!test[i].skipmsg) {
mysql= mysql_default;
if (test[i].connection & TEST_CONNECTION_NEW)
mysql= test_connect(&test[i]);
if (test[i].connection & TEST_CONNECTION_NONE)
mysql= NULL;
/* run test */
rc= test[i].function(mysql);
if (rc == SKIP)
skip(1, "%s", test[i].name);
else
ok(rc == OK, "%s", test[i].name);
/* if test failed, close and reopen default connection to prevent
errors for further tests */
if ((rc == FAIL || mysql_errno(mysql_default)) && (test[i].connection & TEST_CONNECTION_DEFAULT)) {
mysql_close(mysql_default);
mysql_default= test_connect(&test[i]);
}
/* clear connection: reset default connection or close extra connection */
else if (mysql_default && (test[i].connection & TEST_CONNECTION_DEFAULT)) {
if (reset_connection(mysql))
return; /* default doesn't work anymore */
}
else if (mysql && !(test[i].connection & TEST_CONNECTION_DONT_CLOSE))
{
mysql_close(mysql);
}
} else {
skip(1, "%s", test[i].skipmsg);
}
}
if (this_host)
free(this_host);
if (mysql_default) {
diag("close default");
mysql_close(mysql_default);
}
}

View File

@ -0,0 +1,76 @@
/*
Copyright (c) 2016 MariaDB Corporation 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; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
Some basic tests of the client API.
*/
#include "my_test.h"
#include "ma_common.h"
static int perf1(MYSQL *mysql)
{
int rc;
MYSQL_STMT *stmt;
const char *stmtstr= "SELECT s.emp_no, s.salary, e.emp_no, e.first_name, e.last_name, e.gender FROM salaries s, employees e WHERE s.emp_no = e.emp_no";
rc= mysql_select_db(mysql, "employees");
if (rc)
{
diag("Employees database not installed");
return SKIP;
}
stmt= mysql_stmt_init(mysql);
diag("prepare");
rc= mysql_stmt_prepare(stmt, SL(stmtstr));
check_stmt_rc(rc, stmt);
diag("execute");
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
diag("store");
rc= mysql_stmt_store_result(stmt);
check_stmt_rc(rc, stmt);
diag("fetch");
while (!mysql_stmt_fetch(stmt));
mysql_stmt_close(stmt);
return OK;
}
struct my_tests_st my_tests[] = {
{"perf1", perf1, TEST_CONNECTION_NEW, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

5208
vendor/MDBC/unittest/libmariadb/ps.c vendored Normal file

File diff suppressed because it is too large Load Diff

5484
vendor/MDBC/unittest/libmariadb/ps_bugs.c vendored Normal file

File diff suppressed because it is too large Load Diff

511
vendor/MDBC/unittest/libmariadb/ps_new.c vendored Normal file
View File

@ -0,0 +1,511 @@
/************************************************************************************
Copyright (C) 2012 Monty Program AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
#include "my_test.h"
/* Utility function to verify the field members */
static int test_multi_result(MYSQL *mysql)
{
MYSQL_STMT *stmt;
MYSQL_BIND ps_params[3]; /* input parameter buffers */
MYSQL_BIND rs_bind[3];
int int_data[3]; /* input/output values */
my_bool is_null[3]; /* output value nullability */
int rc, i;
/* set up stored procedure */
rc = mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
check_mysql_rc(rc, mysql);
rc = mysql_query(mysql,
"CREATE PROCEDURE p1("
" IN p_in INT, "
" OUT p_out INT, "
" INOUT p_inout INT) "
"BEGIN "
" SELECT p_in, p_out, p_inout; "
" SET p_in = 100, p_out = 200, p_inout = 300; "
" SELECT p_in, p_out, p_inout; "
"END");
check_mysql_rc(rc, mysql);
/* initialize and prepare CALL statement with parameter placeholders */
stmt = mysql_stmt_init(mysql);
if (!stmt)
{
diag("Could not initialize statement");
exit(1);
}
rc = mysql_stmt_prepare(stmt, "CALL p1(?, ?, ?)", 16);
check_stmt_rc(rc, stmt);
/* initialize parameters: p_in, p_out, p_inout (all INT) */
memset(ps_params, 0, sizeof (ps_params));
ps_params[0].buffer_type = MYSQL_TYPE_LONG;
ps_params[0].buffer = (char *) &int_data[0];
ps_params[0].length = 0;
ps_params[0].is_null = 0;
ps_params[1].buffer_type = MYSQL_TYPE_LONG;
ps_params[1].buffer = (char *) &int_data[1];
ps_params[1].length = 0;
ps_params[1].is_null = 0;
ps_params[2].buffer_type = MYSQL_TYPE_LONG;
ps_params[2].buffer = (char *) &int_data[2];
ps_params[2].length = 0;
ps_params[2].is_null = 0;
/* bind parameters */
rc = mysql_stmt_bind_param(stmt, ps_params);
check_stmt_rc(rc, stmt);
/* assign values to parameters and execute statement */
int_data[0]= 10; /* p_in */
int_data[1]= 20; /* p_out */
int_data[2]= 30; /* p_inout */
rc = mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
FAIL_IF(mysql_stmt_field_count(stmt) != 3, "expected 3 fields");
memset(rs_bind, 0, sizeof (MYSQL_BIND) * 3);
for (i=0; i < 3; i++)
{
rs_bind[i].buffer = (char *) &(int_data[i]);
rs_bind[i].buffer_length = sizeof (int_data);
rs_bind[i].buffer_type = MYSQL_TYPE_LONG;
rs_bind[i].is_null = &is_null[i];
}
rc= mysql_stmt_bind_result(stmt, rs_bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
FAIL_IF(int_data[0] != 10 || int_data[1] != 20 || int_data[2] != 30,
"expected 10 20 30");
rc= mysql_stmt_next_result(stmt);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_bind_result(stmt, rs_bind);
rc= mysql_stmt_fetch(stmt);
FAIL_IF(mysql_stmt_field_count(stmt) != 3, "expected 3 fields");
FAIL_IF(int_data[0] != 100 || int_data[1] != 200 || int_data[2] != 300,
"expected 100 200 300");
FAIL_IF(mysql_stmt_next_result(stmt) != 0, "expected more results");
rc= mysql_stmt_bind_result(stmt, rs_bind);
rc= mysql_stmt_fetch(stmt);
FAIL_IF(mysql_stmt_field_count(stmt) != 2, "expected 2 fields");
FAIL_IF(int_data[0] != 200 || int_data[1] != 300,
"expected 100 200 300");
FAIL_IF(mysql_stmt_next_result(stmt) != 0, "expected more results");
FAIL_IF(mysql_stmt_field_count(stmt) != 0, "expected 0 fields");
rc= mysql_stmt_close(stmt);
rc = mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
check_mysql_rc(rc, mysql);
return OK;
}
int test_sp_params(MYSQL *mysql)
{
int i, rc;
MYSQL_STMT *stmt;
int a[] = {10,20,30};
MYSQL_BIND bind[3];
const char *stmtstr= "CALL P1(?,?,?)";
char res[3][20];
rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19), IN p_in INT, INOUT p_inout INT)"
"BEGIN "
" SET p_in = 300, p_out := 'This is OUT param', p_inout = 200; "
" SELECT p_inout, p_in, substring(p_out, 9);"
"END");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
check_mysql_rc(rc, mysql);
rc= mysql_stmt_prepare(stmt,SL(stmtstr));
check_stmt_rc(rc, stmt);
FAIL_IF(mysql_stmt_param_count(stmt) != 3, "expected param_count=3");
memset(bind, 0, sizeof(MYSQL_BIND) * 3);
for (i=0; i < 3; i++)
{
bind[i].buffer= &a[i];
bind[i].buffer_type= MYSQL_TYPE_LONG;
}
bind[0].buffer_type= MYSQL_TYPE_NULL;
rc= mysql_stmt_bind_param(stmt, bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
memset(res, 0, 60);
memset(bind, 0, sizeof(MYSQL_BIND) * 3);
for (i=0; i < 3; i++)
{
bind[i].buffer_type= MYSQL_TYPE_STRING;
bind[i].buffer_length= 20;
bind[i].buffer= res[i];
}
do {
if (mysql->server_status & SERVER_PS_OUT_PARAMS)
{
diag("out param result set");
FAIL_IF(mysql_stmt_field_count(stmt) != 2, "expected 2 columns");
FAIL_IF(strcmp(stmt->fields[0].org_name, "p_out") != 0, "wrong field name");
FAIL_IF(strcmp(stmt->fields[1].org_name, "p_inout") != 0, "wrong field name");
rc= mysql_stmt_bind_result(stmt, bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
FAIL_IF(strcmp(res[0],"This is OUT param") != 0, "comparison failed");
FAIL_IF(strcmp(res[1],"200") != 0, "comparison failed");
}
else
if (mysql_stmt_field_count(stmt))
{
diag("sp result set");
FAIL_IF(mysql_stmt_field_count(stmt) != 3, "expected 3 columns");
rc= mysql_stmt_bind_result(stmt, bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
FAIL_IF(strcmp(res[0],"200") != 0, "comparison failed");
FAIL_IF(strcmp(res[1],"300") != 0, "comparison failed");
FAIL_IF(strcmp(res[2],"OUT param") != 0, "comparison failed");
}
} while (mysql_stmt_next_result(stmt) == 0);
rc= mysql_stmt_close(stmt);
return OK;
}
int test_sp_reset(MYSQL *mysql)
{
int i, rc;
MYSQL_STMT *stmt;
int a[] = {10,20,30};
MYSQL_BIND bind[3];
const char *stmtstr= "CALL P1(?,?,?)";
rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19), IN p_in INT, INOUT p_inout INT)"
"BEGIN "
" SET p_in = 300, p_out := 'This is OUT param', p_inout = 200; "
" SELECT p_inout, p_in, substring(p_out, 9);"
"END");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
check_mysql_rc(rc, mysql);
rc= mysql_stmt_prepare(stmt,SL(stmtstr));
check_stmt_rc(rc, stmt);
FAIL_IF(mysql_stmt_param_count(stmt) != 3, "expected param_count=3");
memset(bind, 0, sizeof(MYSQL_BIND) * 3);
for (i=0; i < 3; i++)
{
bind[i].buffer= &a[i];
bind[i].buffer_type= MYSQL_TYPE_LONG;
}
bind[0].buffer_type= MYSQL_TYPE_NULL;
rc= mysql_stmt_bind_param(stmt, bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_reset(stmt);
check_stmt_rc(rc, stmt);
/*connection shouldn't be blocked now */
rc= mysql_query(mysql, "DROP PROCEDURE p1");
check_mysql_rc(rc, mysql);
rc= mysql_stmt_close(stmt);
return OK;
}
int test_sp_reset1(MYSQL *mysql)
{
int rc;
MYSQL_STMT *stmt;
MYSQL_BIND bind[1];
char tmp[20];
const char *stmtstr= "CALL P1(?)";
rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19))"
"BEGIN "
" SET p_out = 'foo';"
" SELECT 'foo' FROM DUAL;"
" SELECT 'bar' FROM DUAL;"
"END");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
check_mysql_rc(rc, mysql);
rc= mysql_stmt_prepare(stmt,SL(stmtstr));
check_stmt_rc(rc, stmt);
memset(tmp, 0, sizeof(tmp));
memset(bind, 0, sizeof(MYSQL_BIND));
bind[0].buffer= tmp;
bind[0].buffer_type= MYSQL_TYPE_STRING;
bind[0].buffer_length= 4;
mysql_stmt_bind_param(stmt, bind);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_store_result(stmt);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_next_result(stmt);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
/* mysql_stmt_reset should set statement in prepared state.
* this means: all subsequent result sets should be flushed.
* Let's try!
*/
rc= mysql_stmt_reset(stmt);
check_stmt_rc(rc, stmt);
rc= mysql_query(mysql, "DROP PROCEDURE p1");
check_mysql_rc(rc, mysql);
mysql_stmt_close(stmt);
return OK;
}
int test_sp_reset2(MYSQL *mysql)
{
int rc, i;
MYSQL_STMT *stmt;
MYSQL_BIND bind[4];
long l[4];
const char *stmtstr= "CALL P1()";
memset(l, 0, sizeof(l));
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE PROCEDURE p1()"
"BEGIN "
" SET @a:=1;"
" INSERT INTO t1 VALUES(1);"
" SELECT 1 FROM DUAL;"
" SELECT 2,3 FROM DUAL;"
" INSERT INTO t1 VALUES(2);"
" SELECT 3,4,5 FROM DUAL;"
" SELECT 4,5,6,7 FROM DUAL;"
"END");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
check_mysql_rc(rc, mysql);
rc= mysql_stmt_prepare(stmt,SL(stmtstr));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
memset(bind, 0, sizeof(MYSQL_BIND) * 4);
for (i=0; i < 4; i++)
{
bind[i].buffer_type= MYSQL_TYPE_LONG;
bind[i].buffer= &l[i];
}
rc= mysql_stmt_bind_result(stmt, bind);
check_stmt_rc(rc, stmt);
while (rc != MYSQL_NO_DATA)
{
rc= mysql_stmt_fetch(stmt);
diag("l=%ld", l[0]);
}
rc= mysql_stmt_next_result(stmt);
check_stmt_rc(rc, stmt);
/* now rebind since we expect 2 columns */
rc= mysql_stmt_bind_result(stmt, bind);
check_stmt_rc(rc, stmt);
while (rc != MYSQL_NO_DATA)
{
rc= mysql_stmt_fetch(stmt);
diag("l=%ld l=%ld", l[0], l[1]);
}
rc= mysql_stmt_next_result(stmt);
check_stmt_rc(rc, stmt);
/* now rebind since we expect 2 columns */
rc= mysql_stmt_bind_result(stmt, bind);
check_stmt_rc(rc, stmt);
while (rc != MYSQL_NO_DATA)
{
rc= mysql_stmt_fetch(stmt);
diag("l=%ld l=%ld l=%ld", l[0], l[1], l[2]);
}
rc= mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP PROCEDURE p1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
return OK;
}
int test_query(MYSQL *mysql)
{
int rc;
int i;
MYSQL_STMT *stmt;
MYSQL_BIND bind[1];
char tmp[20];
const char *stmtstr= "CALL P1(?)";
rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19))"
"BEGIN "
" SET p_out = 'foo';"
" SELECT 1 FROM DUAL;"
"END");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
check_mysql_rc(rc, mysql);
rc= mysql_stmt_prepare(stmt,SL(stmtstr));
check_stmt_rc(rc, stmt);
for (i=0; i < 1000; i++)
{
int status;
memset(tmp, 0, sizeof(tmp));
memset(bind, 0, sizeof(MYSQL_BIND));
bind[0].buffer= tmp;
bind[0].buffer_type= MYSQL_TYPE_STRING;
bind[0].buffer_length= 4;
mysql_stmt_bind_param(stmt, bind);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
do {
if (stmt->field_count)
{
mysql_stmt_bind_result(stmt, bind);
rc= mysql_stmt_store_result(stmt);
check_stmt_rc(rc, stmt);
while(mysql_stmt_fetch(stmt) == 0);
rc= mysql_stmt_free_result(stmt);
check_stmt_rc(rc, stmt);
}
status= mysql_stmt_next_result(stmt);
if (status == 1)
check_stmt_rc(status, stmt);
} while (status == 0);
rc= mysql_stmt_reset(stmt);
if (rc)
diag("reset failed after %d iterations", i);
check_stmt_rc(rc, stmt);
}
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
check_mysql_rc(rc, mysql);
return OK;
}
struct my_tests_st my_tests[] = {
{"test_query", test_query, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_RESULTS , NULL , NULL},
{"test_sp_params", test_sp_params, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_STATEMENTS, NULL , NULL},
{"test_sp_reset", test_sp_reset, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_STATEMENTS, NULL , NULL},
{"test_sp_reset1", test_sp_reset1, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_STATEMENTS, NULL , NULL},
{"test_sp_reset2", test_sp_reset2, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_STATEMENTS, NULL , NULL},
{"test_multi_result", test_multi_result, TEST_CONNECTION_DEFAULT, CLIENT_MULTI_STATEMENTS, NULL , NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

1102
vendor/MDBC/unittest/libmariadb/result.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
/*
Copyright (c) 2018 MariaDB Corporation AB
The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
Some basic tests of the client API.
*/
#include "my_test.h"
#include "mariadb_rpl.h"
static int test_rpl_01(MYSQL *mysql)
{
MARIADB_RPL_EVENT *event= NULL;
MARIADB_RPL *rpl= mariadb_rpl_init(mysql);
mysql_query(mysql, "SET @mariadb_slave_capability=4");
mysql_query(mysql, "SET NAMES latin1");
mysql_query(mysql, "SET @slave_gtid_strict_mode=1");
mysql_query(mysql, "SET @slave_gtid_ignore_duplicates=1");
mysql_query(mysql, "SET NAMES utf8");
mysql_query(mysql, "SET @master_binlog_checksum= @@global.binlog_checksum");
rpl->server_id= 12;
rpl->start_position= 4;
rpl->flags= MARIADB_RPL_BINLOG_SEND_ANNOTATE_ROWS;
if (mariadb_rpl_open(rpl))
return FAIL;
while((event= mariadb_rpl_fetch(rpl, event)))
{
diag("event: %d\n", event->event_type);
}
mariadb_free_rpl_event(event);
mariadb_rpl_close(rpl);
return OK;
}
struct my_tests_st my_tests[] = {
{"test_rpl_01", test_rpl_01, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

91
vendor/MDBC/unittest/libmariadb/sp.c vendored Normal file
View File

@ -0,0 +1,91 @@
/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "my_test.h"
/* Bug#15752 "Lost connection to MySQL server when calling a SP from C API" */
static int test_bug15752(MYSQL *mysql)
{
int rc, i;
const int ITERATION_COUNT= 100;
const char *query= "CALL p1()";
rc= mysql_query(mysql, "drop procedure if exists p1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create procedure p1() select 1");
check_mysql_rc(rc, mysql);
rc= mysql_real_query(mysql, SL(query));
check_mysql_rc(rc, mysql);
mysql_free_result(mysql_store_result(mysql));
rc= mysql_real_query(mysql, SL(query));
FAIL_UNLESS(rc && mysql_errno(mysql) == CR_COMMANDS_OUT_OF_SYNC, "Error expected");
rc= mysql_next_result(mysql);
check_mysql_rc(rc, mysql);
mysql_free_result(mysql_store_result(mysql));
rc= mysql_next_result(mysql);
FAIL_IF(rc != -1, "rc != -1");
for (i = 0; i < ITERATION_COUNT; i++)
{
rc= mysql_real_query(mysql, SL(query));
check_mysql_rc(rc, mysql);
mysql_free_result(mysql_store_result(mysql));
rc= mysql_next_result(mysql);
check_mysql_rc(rc, mysql);
mysql_free_result(mysql_store_result(mysql));
rc= mysql_next_result(mysql);
FAIL_IF(rc != -1, "rc != -1");
}
rc= mysql_query(mysql, "drop procedure p1");
check_mysql_rc(rc, mysql);
return OK;
}
struct my_tests_st my_tests[] = {
{"test_bug15752", test_bug15752, TEST_CONNECTION_NEW, 0, NULL , NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

1424
vendor/MDBC/unittest/libmariadb/ssl.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,164 @@
/*
*/
#include "my_test.h"
#include "ma_pvio.h"
static int aurora1(MYSQL *unused __attribute__((unused)))
{
int rc;
my_bool read_only= 1;
char *primary, *my_schema;
MYSQL_RES *res;
MYSQL *mysql= mysql_init(NULL);
if (!mysql_real_connect(mysql, hostname, username, password, schema, port, NULL, 0))
{
diag("Error: %s", mysql_error(mysql));
mysql_close(mysql);
return FAIL;
}
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1 (a int, b varchar(20))");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1, 'foo'), (2, 'bar')");
check_mysql_rc(rc, mysql);
mariadb_get_infov(mysql, MARIADB_CONNECTION_HOST, &primary);
diag("primary: %s", primary);
mysql_options(mysql, MARIADB_OPT_CONNECTION_READ_ONLY, &read_only);
/* ensure, that this is a replica, so INSERT should fail */
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (3, 'error')");
if (rc)
diag("Expected error: %s", mysql_error(mysql));
rc= mysql_query(mysql, "SELECT a, b FROM t1");
check_mysql_rc(rc, mysql);
res= mysql_store_result(mysql);
diag("Num_rows: %lld", mysql_num_rows(res));
mysql_free_result(res);
mariadb_get_infov(mysql, MARIADB_CONNECTION_SCHEMA, &my_schema);
diag("db: %s", my_schema);
mysql_close(mysql);
return OK;
}
static int test_wrong_user(MYSQL *unused __attribute__((unused)))
{
MYSQL *mysql= mysql_init(NULL);
if (mysql_real_connect(mysql, hostname, "wrong_user", NULL, NULL, 0, NULL, 0))
{
diag("Error expected");
mysql_close(mysql);
return FAIL;
}
mysql_close(mysql);
return OK;
}
static int test_reconnect(MYSQL *unused __attribute__((unused)))
{
MYSQL *mysql= mysql_init(NULL);
MYSQL_RES *res;
my_bool read_only= 1;
int rc;
my_bool reconnect= 1;
char *aurora_host;
mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
if (!mysql_real_connect(mysql, hostname, username, password, schema, port, NULL, 0))
{
diag("Error: %s", mysql_error(mysql));
mysql_close(mysql);
return FAIL;
}
mariadb_get_infov(mysql, MARIADB_CONNECTION_HOST, &aurora_host);
diag("host: %s", aurora_host);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS tx01");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE tx01 (a int)");
check_mysql_rc(rc, mysql);
/* we force cluster restart and promoting new primary:
* we wait for 50 seconds - however there is no guarantee that
* cluster was restarted already - so this test might fail */
rc= system("/usr/local/aws/bin/aws rds failover-db-cluster --db-cluster-identifier instance-1-cluster");
diag("aws return code: %d", rc);
sleep(50);
diag("Q1");
rc= mysql_query(mysql, "INSERT INTO tx01 VALUES (1)");
if (!rc)
diag("error expected!");
diag("Error: %s", mysql_error(mysql));
diag("Q2");
rc= mysql_query(mysql, "INSERT INTO tx01 VALUES (1)");
if (rc)
{
diag("no error expected!");
diag("Error: %s", mysql_error(mysql));
diag("host: %s", mysql->host);
}
else
{
mariadb_get_infov(mysql, MARIADB_CONNECTION_HOST, &aurora_host);
diag("host: %s", aurora_host);
}
mysql_options(mysql, MARIADB_OPT_CONNECTION_READ_ONLY, &read_only);
rc= mysql_query(mysql, "SELECT * from tx01");
check_mysql_rc(rc, mysql);
if ((res= mysql_store_result(mysql)))
{
diag("num_rows: %lld", mysql_num_rows(res));
mysql_free_result(res);
}
mariadb_get_infov(mysql, MARIADB_CONNECTION_HOST, &aurora_host);
diag("host: %s", aurora_host);
mysql_close(mysql);
return OK;
}
struct my_tests_st my_tests[] = {
{"aurora1", aurora1, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"test_wrong_user", test_wrong_user, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"test_reconnect", test_reconnect, TEST_CONNECTION_NONE, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
mysql_library_init(0,0,NULL);
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
mysql_server_end();
return(exit_status());
}

View File

@ -0,0 +1,72 @@
/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
Some basic tests of the client API.
*/
#include "my_test.h"
static int test_conc_173(MYSQL *unused __attribute__((unused)))
{
MYSQL mysql;
int arg;
int i=0;
for (;;)
{
mysql_init(&mysql);
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
mysql_options(&mysql, MYSQL_OPT_COMPRESS, 0);
mysql_options(&mysql, MYSQL_OPT_NAMED_PIPE, 0);
arg = MYSQL_PROTOCOL_SOCKET;
mysql_options(&mysql, MYSQL_OPT_PROTOCOL, &arg);
if(!mysql_real_connect(&mysql, hostname, username, password, schema, port, 0, 0)) {
fprintf(stderr, "Failed to connect to database after %d iterations: Error: %s\n", i, mysql_error(&mysql));
return 1;
}
mysql_close(&mysql);
}
return OK;
}
struct my_tests_st my_tests[] = {
{"test_conc_173", test_conc_173, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

180
vendor/MDBC/unittest/libmariadb/thread.c vendored Normal file
View File

@ -0,0 +1,180 @@
/*
*/
#include "my_test.h"
#include <ma_pthread.h>
static int basic_connect(MYSQL *unused __attribute__((unused)))
{
MYSQL_ROW row;
MYSQL_RES *res;
MYSQL_FIELD *field;
int rc;
MYSQL *my= mysql_init(NULL);
FAIL_IF(!my, "mysql_init() failed");
FAIL_IF(!my_test_connect(my, hostname, username, password, schema,
port, socketname, 0), mysql_error(my));
rc= mysql_query(my, "SELECT @@version");
check_mysql_rc(rc, my);
res= mysql_store_result(my);
FAIL_IF(!res, mysql_error(my));
field= mysql_fetch_fields(res);
FAIL_IF(!field, "Couldn't fetch fields");
while ((row= mysql_fetch_row(res)) != NULL)
{
FAIL_IF(mysql_num_fields(res) != 1, "Got the wrong number of fields");
}
FAIL_IF(mysql_errno(my), mysql_error(my));
mysql_free_result(res);
mysql_close(my);
return OK;
}
pthread_mutex_t LOCK_test;
#ifndef _WIN32
int thread_conc27(void);
#else
DWORD WINAPI thread_conc27(void);
#endif
#define THREAD_NUM 100
/* run this test as root and increase the number of handles (ulimit -n) */
static int test_conc_27(MYSQL *mysql)
{
int rc;
int i;
MYSQL_ROW row;
MYSQL_RES *res;
#ifndef _WIN32
pthread_t threads[THREAD_NUM];
#else
HANDLE hthreads[THREAD_NUM];
DWORD threads[THREAD_NUM];
#endif
diag("please run this test manually as root");
return SKIP;
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t_conc27");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t_conc27(a int)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t_conc27 VALUES(0)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SET @a:=@@max_connections");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SET GLOBAL max_connections=100000");
check_mysql_rc(rc, mysql);
pthread_mutex_init(&LOCK_test, NULL);
for (i=0; i < THREAD_NUM; i++)
{
#ifndef _WIN32
pthread_create(&threads[i], NULL, (void *)thread_conc27, NULL);
#else
hthreads[i]= CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_conc27, NULL, 0, &threads[i]);
if (hthreads[i]==NULL)
diag("error while starting thread");
#endif
}
for (i=0; i < THREAD_NUM; i++)
{
#ifndef _WIN32
pthread_join(threads[i], NULL);
#else
WaitForSingleObject(hthreads[i], INFINITE);
#endif
}
pthread_mutex_destroy(&LOCK_test);
rc= mysql_query(mysql, "SET GLOBAL max_connections=@a");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SELECT a FROM t_conc27");
check_mysql_rc(rc,mysql);
res= mysql_store_result(mysql);
FAIL_IF(!res, "invalid result");
row= mysql_fetch_row(res);
FAIL_IF(!row, "can't fetch row");
diag("row=%s", row[0]);
FAIL_IF(atoi(row[0]) != THREAD_NUM, "expected value THREAD_NUM");
mysql_free_result(res);
rc= mysql_query(mysql, "DROP TABLE t_conc27");
check_mysql_rc(rc,mysql);
return OK;
}
#ifndef _WIN32
int thread_conc27(void)
#else
DWORD WINAPI thread_conc27(void)
#endif
{
MYSQL *mysql;
int rc;
MYSQL_RES *res;
mysql_thread_init();
mysql= mysql_init(NULL);
if(!my_test_connect(mysql, hostname, username, password, schema,
port, socketname, 0))
{
diag(">Error: %s", mysql_error(mysql));
mysql_close(mysql);
mysql_thread_end();
goto end;
}
pthread_mutex_lock(&LOCK_test);
rc= mysql_query(mysql, "UPDATE t_conc27 SET a=a+1");
check_mysql_rc(rc, mysql);
pthread_mutex_unlock(&LOCK_test);
check_mysql_rc(rc, mysql);
if ((res= mysql_store_result(mysql)))
mysql_free_result(res);
mysql_close(mysql);
end:
mysql_thread_end();
return 0;
}
struct my_tests_st my_tests[] = {
{"basic_connect", basic_connect, TEST_CONNECTION_NONE, 0, NULL, NULL},
{"test_conc_27", test_conc_27, TEST_CONNECTION_NEW, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
mysql_library_init(0,0,NULL);
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
mysql_server_end();
return(exit_status());
}

697
vendor/MDBC/unittest/libmariadb/view.c vendored Normal file
View File

@ -0,0 +1,697 @@
/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "my_test.h"
static int test_view(MYSQL *mysql)
{
MYSQL_STMT *stmt;
int rc, i;
MYSQL_BIND my_bind[1];
char str_data[50];
ulong length = 0L;
my_bool is_null = 0;
const char *query=
"SELECT COUNT(*) FROM v1 WHERE SERVERNAME=?";
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2,t3,v1");
check_mysql_rc(rc, mysql);
rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1,t2,t3");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,"CREATE TABLE t1 ("
" SERVERGRP varchar(20) NOT NULL default '', "
" DBINSTANCE varchar(20) NOT NULL default '', "
" PRIMARY KEY (SERVERGRP)) "
" CHARSET=latin1 collate=latin1_bin");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,"CREATE TABLE t2 ("
" SERVERNAME varchar(20) NOT NULL, "
" SERVERGRP varchar(20) NOT NULL, "
" PRIMARY KEY (SERVERNAME)) "
" CHARSET=latin1 COLLATE latin1_bin");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,
"CREATE TABLE t3 ("
" SERVERGRP varchar(20) BINARY NOT NULL, "
" TABNAME varchar(30) NOT NULL, MAPSTATE char(1) NOT NULL, "
" ACTSTATE char(1) NOT NULL , "
" LOCAL_NAME varchar(30) NOT NULL, "
" CHG_DATE varchar(8) NOT NULL default '00000000', "
" CHG_TIME varchar(6) NOT NULL default '000000', "
" MXUSER varchar(12) NOT NULL default '', "
" PRIMARY KEY (SERVERGRP, TABNAME, MAPSTATE, ACTSTATE, "
" LOCAL_NAME)) CHARSET=latin1 COLLATE latin1_bin");
check_mysql_rc(rc, mysql);
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' '))");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, SL(query));
check_stmt_rc(rc, stmt);
strcpy(str_data, "TEST");
memset(my_bind, '\0', sizeof(MYSQL_BIND));
my_bind[0].buffer_type= MYSQL_TYPE_STRING;
my_bind[0].buffer= (char *)&str_data;
my_bind[0].buffer_length= 50;
my_bind[0].length= &length;
length= 4;
my_bind[0].is_null= &is_null;
rc= mysql_stmt_bind_param(stmt, my_bind);
check_stmt_rc(rc, stmt);
for (i= 0; i < 3; i++)
{
int rowcount= 0;
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
rowcount++;
FAIL_IF(rowcount != 1, "Expected 1 row");
}
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP TABLE t1,t2,t3");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP VIEW v1");
check_mysql_rc(rc, mysql);
return OK;
}
static int test_view_where(MYSQL *mysql)
{
MYSQL_STMT *stmt;
int rc, i;
const char *query=
"select v1.c,v2.c from v1, v2";
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1,v2");
check_mysql_rc(rc, mysql);
rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,v2,t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,"CREATE TABLE t1 (a int, b int)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,"insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,"create view v1 (c) as select b from t1 where a<3");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,"create view v2 (c) as select b from t1 where a>=3");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, SL(query));
check_stmt_rc(rc, stmt);
for (i= 0; i < 3; i++)
{
int rowcount= 0;
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
rowcount++;
FAIL_UNLESS(4 == rowcount, "Expected 4 rows");
}
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP TABLE t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP VIEW v1, v2");
check_mysql_rc(rc, mysql);
return OK;
}
static int test_view_2where(MYSQL *mysql)
{
MYSQL_STMT *stmt;
int rc, i;
MYSQL_BIND my_bind[8];
char params[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 = ?";
rc= mysql_query(mysql, "DROP TABLE IF EXISTS LTDX");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP VIEW IF EXISTS V_LTDX");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,
"CREATE TABLE LTDX (MANDT char(3) NOT NULL default '000', "
" RELID char(2) NOT NULL, REPORT varchar(40) NOT NULL,"
" HANDLE varchar(4) NOT NULL, LOG_GROUP varchar(4) NOT NULL,"
" USERNAME varchar(12) NOT NULL,"
" VARIANT varchar(12) NOT NULL,"
" TYPE char(1) NOT NULL, SRTF2 int(11) NOT NULL,"
" VERSION varchar(6) NOT NULL default '000000',"
" ERFDAT varchar(8) NOT NULL default '00000000',"
" ERFTIME varchar(6) NOT NULL default '000000',"
" ERFNAME varchar(12) NOT NULL,"
" AEDAT varchar(8) NOT NULL default '00000000',"
" AETIME varchar(6) NOT NULL default '000000',"
" AENAME varchar(12) NOT NULL,"
" DEPENDVARS varchar(10) NOT NULL,"
" INACTIVE char(1) NOT NULL, CLUSTR smallint(6) NOT NULL,"
" CLUSTD blob,"
" PRIMARY KEY (MANDT, RELID, REPORT, HANDLE, LOG_GROUP, "
"USERNAME, VARIANT, TYPE, SRTF2))"
" CHARSET=latin1 COLLATE latin1_bin");
check_mysql_rc(rc, mysql);
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)");
check_mysql_rc(rc, mysql);
memset(my_bind, '\0', sizeof(MYSQL_BIND));
for (i=0; i < 8; i++) {
strcpy(params[i], "1");
my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
my_bind[i].buffer = (char *)&params[i];
my_bind[i].buffer_length = 1;
my_bind[i].is_null = 0;
length[i] = 1;
my_bind[i].length = &length[i];
}
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, SL(query));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_bind_param(stmt, my_bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_fetch(stmt);
FAIL_UNLESS(MYSQL_NO_DATA == rc, "Expected 0 rows");
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP VIEW V_LTDX");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE LTDX");
check_mysql_rc(rc, mysql);
return OK;
}
static int test_view_star(MYSQL *mysql)
{
MYSQL_STMT *stmt;
int rc, i;
MYSQL_BIND my_bind[8];
char params[8][100];
ulong length[8];
const char *query= "SELECT * FROM vt1 WHERE a IN (?,?)";
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, vt1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP VIEW IF EXISTS t1, vt1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1");
check_mysql_rc(rc, mysql);
memset(my_bind, '\0', sizeof(MYSQL_BIND));
for (i= 0; i < 2; i++) {
sprintf((char *)&params[i], "%d", i);
my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
my_bind[i].buffer = (char *)&params[i];
my_bind[i].buffer_length = 100;
my_bind[i].is_null = 0;
my_bind[i].length = &length[i];
length[i] = 1;
}
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, SL(query));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_bind_param(stmt, my_bind);
check_stmt_rc(rc, stmt);
for (i= 0; i < 3; i++)
{
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_fetch(stmt);
FAIL_UNLESS(MYSQL_NO_DATA == rc, "Expected 0 rows");
}
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP TABLE t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP VIEW vt1");
check_mysql_rc(rc, mysql);
return OK;
}
static int test_view_insert(MYSQL *mysql)
{
MYSQL_STMT *insert_stmt, *select_stmt;
int rc, i;
MYSQL_BIND my_bind[1];
int my_val = 0;
ulong my_length = 0L;
my_bool my_null = 0;
const char *query=
"insert into v1 values (?)";
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1");
check_mysql_rc(rc, mysql);
rc = mysql_query(mysql, "DROP VIEW IF EXISTS t1,v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,"create table t1 (a int, primary key (a))");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create view v1 as select a from t1 where a>=1");
check_mysql_rc(rc, mysql);
insert_stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(insert_stmt, SL(query));
check_stmt_rc(rc, insert_stmt);
query= "select * from t1";
select_stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(select_stmt, SL(query));
check_stmt_rc(rc, select_stmt);
memset(my_bind, '\0', sizeof(MYSQL_BIND));
my_bind[0].buffer_type = MYSQL_TYPE_LONG;
my_bind[0].buffer = (char *)&my_val;
my_bind[0].length = &my_length;
my_bind[0].is_null = &my_null;
rc= mysql_stmt_bind_param(insert_stmt, my_bind);
check_stmt_rc(rc, select_stmt);
for (i= 0; i < 3; i++)
{
int rowcount= 0;
my_val= i;
rc= mysql_stmt_execute(insert_stmt);
check_stmt_rc(rc, insert_stmt);;
rc= mysql_stmt_execute(select_stmt);
check_stmt_rc(rc, select_stmt);;
while (mysql_stmt_fetch(select_stmt) != MYSQL_NO_DATA)
rowcount++;
FAIL_UNLESS((i+1) == rowcount, "rowcount != i+1");
}
mysql_stmt_close(insert_stmt);
mysql_stmt_close(select_stmt);
rc= mysql_query(mysql, "DROP VIEW v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE t1");
check_mysql_rc(rc, mysql);
return OK;
}
static int test_left_join_view(MYSQL *mysql)
{
MYSQL_STMT *stmt;
int rc, i;
const char *query=
"select t1.a, v1.x from t1 left join v1 on (t1.a= v1.x);";
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1");
check_mysql_rc(rc, mysql);
rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,"CREATE TABLE t1 (a int)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,"insert into t1 values (1), (2), (3)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,"create view v1 (x) as select a from t1 where a > 1");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, SL(query));
check_stmt_rc(rc, stmt);
for (i= 0; i < 3; i++)
{
int rowcount= 0;
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
rowcount++;
FAIL_UNLESS(3 == rowcount, "Expected 3 rows");
}
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP VIEW v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE t1");
check_mysql_rc(rc, mysql);
return OK;
}
static int test_view_insert_fields(MYSQL *mysql)
{
MYSQL_STMT *stmt;
char parm[11][1000];
ulong l[11];
int rc, i;
int rowcount= 0;
MYSQL_BIND my_bind[11];
const char *query= "INSERT INTO `v1` ( `K1C4` ,`K2C4` ,`K3C4` ,`K4N4` ,`F1C4` ,`F2I4` ,`F3N5` ,`F7F8` ,`F6N4` ,`F5C8` ,`F9D8` ) VALUES( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? )";
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP VIEW IF EXISTS t1, v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql,
"CREATE TABLE t1 (K1C4 varchar(4) NOT NULL,"
"K2C4 varchar(4) NOT NULL, K3C4 varchar(4) NOT NULL,"
"K4N4 varchar(4) NOT NULL default '0000',"
"F1C4 varchar(4) NOT NULL, F2I4 int(11) NOT NULL,"
"F3N5 varchar(5) NOT NULL default '00000',"
"F4I4 int(11) NOT NULL default '0', F5C8 varchar(8) NOT NULL,"
"F6N4 varchar(4) NOT NULL default '0000',"
"F7F8 double NOT NULL default '0',"
"F8F8 double NOT NULL default '0',"
"F9D8 decimal(8,2) NOT NULL default '0.00',"
"PRIMARY KEY (K1C4,K2C4,K3C4,K4N4))");
check_mysql_rc(rc, mysql);
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");
memset(my_bind, '\0', sizeof(my_bind));
for (i= 0; i < 11; i++)
{
l[i]= 20;
my_bind[i].buffer_type= MYSQL_TYPE_STRING;
my_bind[i].is_null= 0;
my_bind[i].buffer= (char *)&parm[i];
strcpy(parm[i], "1");
my_bind[i].buffer_length= 2;
my_bind[i].length= &l[i];
}
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, SL(query));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_bind_param(stmt, my_bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
mysql_stmt_close(stmt);
query= "select * from t1";
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, SL(query));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
rowcount++;
FAIL_UNLESS(1 == rowcount, "Expected 1 row");
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP VIEW v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE t1");
check_mysql_rc(rc, mysql);
return OK;
}
static int test_view_sp_list_fields(MYSQL *mysql)
{
int rc;
MYSQL_RES *res;
MYSQL_ROW row;
int skip;
/* skip this test if bin_log is on */
rc= mysql_query(mysql, "SHOW VARIABLES LIKE 'log_bin'");
check_mysql_rc(rc, mysql);
res= mysql_store_result(mysql);
FAIL_IF(!res, "empty/invalid resultset");
row = mysql_fetch_row(res);
skip= (strcmp((char *)row[1], "ON") == 0);
mysql_free_result(res);
if (skip) {
diag("bin_log is ON -> skip");
return SKIP;
}
rc= mysql_query(mysql, "DROP FUNCTION IF EXISTS f1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS v1, t1, t2");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1, t1, t2");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create function f1 () returns int return 5");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create table t1 (s1 char,s2 char)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create table t2 (s1 int);");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create view v1 as select s2,sum(s1) - \
count(s2) as vx from t1 group by s2 having sum(s1) - count(s2) < (select f1() \
from t2);");
check_mysql_rc(rc, mysql);
res= mysql_list_fields(mysql, "v1", NullS);
FAIL_UNLESS(res != 0 && mysql_num_fields(res) != 0, "0 Fields");
rc= mysql_query(mysql, "DROP FUNCTION f1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP VIEW v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE t1, t2");
mysql_free_result(res);
check_mysql_rc(rc, mysql);
return OK;
}
static int test_bug19671(MYSQL *mysql)
{
MYSQL_RES *result;
MYSQL_FIELD *field;
int rc, retcode= OK;
rc= mysql_query(mysql, "set sql_mode=''");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "drop table if exists t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "drop view if exists v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create table t1(f1 int)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create view v1 as select va.* from t1 va");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "SELECT * FROM v1");
check_mysql_rc(rc, mysql);
result= mysql_store_result(mysql);
FAIL_IF(!result, "Invalid result set");
field= mysql_fetch_field(result);
FAIL_IF(!field, "Can't fetch field");
if (strcmp(field->table, "v1") != 0) {
diag("Wrong value '%s' for field_table. Expected 'v1'. (%s: %d)", field->table, __FILE__, __LINE__);
retcode= FAIL;
}
mysql_free_result(result);
rc= mysql_query(mysql, "drop view v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "drop table t1");
check_mysql_rc(rc, mysql);
return retcode;
}
/*
Bug#11111: fetch from view returns wrong data
*/
static int test_bug11111(MYSQL *mysql)
{
MYSQL_STMT *stmt;
MYSQL_BIND my_bind[2];
char buf[2][20];
ulong len[2];
int i;
int rc;
const char *query= "SELECT DISTINCT f1,ff2 FROM v1";
rc= mysql_query(mysql, "drop table if exists t1, t2, v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "drop view if exists t1, t2, v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create table t1 (f1 int, f2 int)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create table t2 (ff1 int, ff2 int)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "create view v1 as select * from t1, t2 where f1=ff1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "insert into t1 values (1,1), (2,2), (3,3)");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "insert into t2 values (1,1), (2,2), (3,3)");
check_mysql_rc(rc, mysql);
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, SL(query));
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
memset(my_bind, '\0', sizeof(my_bind));
for (i=0; i < 2; i++)
{
my_bind[i].buffer_type= MYSQL_TYPE_STRING;
my_bind[i].buffer= (uchar* *)&buf[i];
my_bind[i].buffer_length= 20;
my_bind[i].length= &len[i];
}
rc= mysql_stmt_bind_result(stmt, my_bind);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);
FAIL_UNLESS(!strcmp(buf[1],"1"), "buf[1] != '1'");
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "drop view v1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "drop table t1, t2");
check_mysql_rc(rc, mysql);
return OK;
}
/**
Bug#29306 Truncated data in MS Access with decimal (3,1) columns in a VIEW
*/
static int test_bug29306(MYSQL *mysql)
{
MYSQL_FIELD *field;
int rc;
MYSQL_RES *res;
rc= mysql_query(mysql, "DROP TABLE IF EXISTS tab17557");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP VIEW IF EXISTS view17557");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE tab17557 (dd decimal (3,1))");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE VIEW view17557 as SELECT dd FROM tab17557");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO tab17557 VALUES (7.6)");
check_mysql_rc(rc, mysql);
/* Checking the view */
res= mysql_list_fields(mysql, "view17557", NULL);
while ((field= mysql_fetch_field(res)))
{
FAIL_UNLESS(field->decimals == 1, "field->decimals != 1");
}
mysql_free_result(res);
rc= mysql_query(mysql, "DROP TABLE tab17557");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP VIEW view17557");
check_mysql_rc(rc, mysql);
return OK;
}
struct my_tests_st my_tests[] = {
{"test_view", test_view, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_view_where", test_view_where, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_view_2where", test_view_2where, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_view_star", test_view_star, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_view_insert", test_view_insert, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_left_join_view", test_left_join_view, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_view_insert_fields", test_view_insert_fields, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_view_sp_list_fields", test_view_sp_list_fields,TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_bug19671", test_bug19671, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_bug29306", test_bug29306, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{"test_bug11111", test_bug11111, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};
int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);
get_envvars();
run_tests(my_tests);
return(exit_status());
}

View File

@ -0,0 +1,19 @@
# Copyright (C) 2007 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; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
INCLUDE_DIRECTORIES(${CC_SOURCE_DIR}/include ${CC_SOURCE_DIR}/zlib
${CC_BINARY_DIR}/include)
ADD_LIBRARY(cctap tap.c)

1156
vendor/MDBC/unittest/mytap/Doxyfile vendored Normal file

File diff suppressed because it is too large Load Diff

33
vendor/MDBC/unittest/mytap/t/basic-t.c vendored Normal file
View File

@ -0,0 +1,33 @@
/* Copyright (C) 2006 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; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "my_config.h"
#include <stdlib.h>
#include "../tap.h"
int main() {
plan(5);
ok(1 == 1, "testing basic functions");
ok(2 == 2, " ");
ok(3 == 3, NULL);
if (1 == 1)
skip(2, "Sensa fragoli");
else {
ok(1 == 2, "Should not be run at all");
ok(1, "This one neither");
}
return exit_status();
}

600
vendor/MDBC/unittest/mytap/tap.c vendored Normal file
View File

@ -0,0 +1,600 @@
/* Copyright (C) 2006 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; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA
Library for providing TAP support for testing C and C++ was written
by Mats Kindahl <mats@mysql.com>.
*/
#include "tap.h"
#include "ma_global.h"
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
/*
Visual Studio 2003 does not know vsnprintf but knows _vsnprintf.
We don't put this #define in config-win.h because we prefer
ma_vsnprintf everywhere instead, except when linking with libmysys
is not desirable - the case here.
*/
#if defined(_MSC_VER) && ( _MSC_VER == 1310 )
#define vsnprintf _vsnprintf
#endif
/**
@defgroup MyTAP_Internal MyTAP Internals
Internal functions and data structures for the MyTAP implementation.
*/
/**
Test data structure.
Data structure containing all information about the test suite.
@ingroup MyTAP_Internal
*/
static TEST_DATA g_test = { 0, 0, 0, "" };
/**
Output stream for test report message.
The macro is just a temporary solution.
@ingroup MyTAP_Internal
*/
#define tapout stdout
/**
Emit the beginning of a test line, that is: "(not) ok", test number,
and description.
To emit the directive, use the emit_dir() function
@ingroup MyTAP_Internal
@see emit_dir
@param pass 'true' if test passed, 'false' otherwise
@param fmt Description of test in printf() format.
@param ap Vararg list for the description string above.
*/
static void
vemit_tap(int pass, char const *fmt, va_list ap)
{
fprintf(tapout, "%sok %d%s",
pass ? "" : "not ",
++g_test.last,
(fmt && *fmt) ? " - " : "");
if (fmt && *fmt)
vfprintf(tapout, fmt, ap);
}
/**
Emit a TAP directive.
TAP directives are comments after that have the form:
@code
ok 1 # skip reason for skipping
not ok 2 # todo some text explaining what remains
@endcode
@ingroup MyTAP_Internal
@param dir Directive as a string
@param why Explanation string
*/
static void
emit_dir(const char *dir, const char *why)
{
fprintf(tapout, " # %s %s", dir, why);
}
/**
Emit a newline to the TAP output stream.
@ingroup MyTAP_Internal
*/
static void
emit_endl()
{
fprintf(tapout, "\n");
}
static void
handle_core_signal(int signo)
{
BAIL_OUT("Signal %d thrown", signo);
}
void
BAIL_OUT(char const *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(tapout, "Bail out! ");
vfprintf(tapout, fmt, ap);
emit_endl();
va_end(ap);
exit(255);
}
void
diag(char const *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(tapout, "# ");
vfprintf(tapout, fmt, ap);
emit_endl();
va_end(ap);
}
typedef struct signal_entry {
int signo;
void (*handler)(int);
} signal_entry;
static signal_entry install_signal[]= {
#ifdef SIGQUIT
{ SIGQUIT, handle_core_signal },
#endif
{ SIGILL, handle_core_signal },
{ SIGABRT, handle_core_signal },
{ SIGFPE, handle_core_signal },
{ SIGSEGV, handle_core_signal }
#ifdef SIGBUS
, { SIGBUS, handle_core_signal }
#endif
#ifdef SIGXCPU
, { SIGXCPU, handle_core_signal }
#endif
#ifdef SIGXCPU
, { SIGXFSZ, handle_core_signal }
#endif
#ifdef SIGXCPU
, { SIGSYS, handle_core_signal }
#endif
#ifdef SIGXCPU
, { SIGTRAP, handle_core_signal }
#endif
};
int skip_big_tests= 1;
void
plan(int const count)
{
char *config= getenv("MYTAP_CONFIG");
size_t i;
if (config)
skip_big_tests= strcmp(config, "big");
setvbuf(tapout, 0, _IONBF, 0); /* provide output at once */
/*
Install signal handler
*/
for (i= 0; i < sizeof(install_signal)/sizeof(*install_signal); ++i)
signal(install_signal[i].signo, install_signal[i].handler);
g_test.plan= count;
switch (count)
{
case NO_PLAN:
break;
default:
if (count > 0)
fprintf(tapout, "1..%d\n", count);
break;
}
}
void
skip_all(char const *reason, ...)
{
va_list ap;
va_start(ap, reason);
fprintf(tapout, "1..0 # skip ");
vfprintf(tapout, reason, ap);
va_end(ap);
exit(0);
}
void
ok(int const pass, char const *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (!pass && *g_test.todo == '\0')
++g_test.failed;
vemit_tap(pass, fmt, ap);
va_end(ap);
if (*g_test.todo != '\0')
emit_dir("todo", g_test.todo);
emit_endl();
}
void
skip(int how_many, char const *const fmt, ...)
{
char reason[80];
if (fmt && *fmt)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(reason, sizeof(reason), fmt, ap);
va_end(ap);
}
else
reason[0] = '\0';
while (how_many-- > 0)
{
va_list ap;
memset((char*) &ap, 0, sizeof(ap)); /* Keep compiler happy */
vemit_tap(1, NULL, ap);
emit_dir("skip", reason);
emit_endl();
}
}
void
todo_start(char const *message, ...)
{
va_list ap;
va_start(ap, message);
vsnprintf(g_test.todo, sizeof(g_test.todo), message, ap);
va_end(ap);
}
void
todo_end()
{
*g_test.todo = '\0';
}
int exit_status() {
/*
If there were no plan, we write one last instead.
*/
if (g_test.plan == NO_PLAN)
plan(g_test.last);
if (g_test.plan != g_test.last)
{
diag("%d tests planned but%s %d executed",
g_test.plan, (g_test.plan > g_test.last ? " only" : ""), g_test.last);
return EXIT_FAILURE;
}
if (g_test.failed > 0)
{
diag("Failed %d tests!", g_test.failed);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/**
@mainpage Testing C and C++ using MyTAP
@section IntroSec Introduction
Unit tests are used to test individual components of a system. In
contrast, functional tests usually test the entire system. The
rationale is that each component should be correct if the system is
to be correct. Unit tests are usually small pieces of code that
tests an individual function, class, a module, or other unit of the
code.
Observe that a correctly functioning system can be built from
"faulty" components. The problem with this approach is that as the
system evolves, the bugs surface in unexpected ways, making
maintenance harder.
The advantages of using unit tests to test components of the system
are several:
- The unit tests can make a more thorough testing than the
functional tests by testing correctness even for pathological use
(which shouldn't be present in the system). This increases the
overall robustness of the system and makes maintenance easier.
- It is easier and faster to find problems with a malfunctioning
component than to find problems in a malfunctioning system. This
shortens the compile-run-edit cycle and therefore improves the
overall performance of development.
- The component has to support at least two uses: in the system and
in a unit test. This leads to more generic and stable interfaces
and in addition promotes the development of reusable components.
For example, the following are typical functional tests:
- Does transactions work according to specifications?
- Can we connect a client to the server and execute statements?
In contrast, the following are typical unit tests:
- Can the 'String' class handle a specified list of character sets?
- Does all operations for 'my_bitmap' produce the correct result?
- Does all the NIST test vectors for the AES implementation encrypt
correctly?
@section UnitTest Writing unit tests
The purpose of writing unit tests is to use them to drive component
development towards a solution that passes the tests. This means that the
unit tests has to be as complete as possible, testing at least:
- Normal input
- Borderline cases
- Faulty input
- Error handling
- Bad environment
@subsection NormalSubSec Normal input
This is to test that the component have the expected behaviour.
This is just plain simple: test that it works. For example, test
that you can unpack what you packed, adding gives the sum, pincing
the duck makes it quack.
This is what everybody does when they write tests.
@subsection BorderlineTests Borderline cases
If you have a size anywhere for your component, does it work for
size 1? Size 0? Sizes close to <code>UINT_MAX</code>?
It might not be sensible to have a size 0, so in this case it is
not a borderline case, but rather a faulty input (see @ref
FaultyInputTests).
@subsection FaultyInputTests Faulty input
Does your bitmap handle 0 bits size? Well, it might not be designed
for it, but is should <em>not</em> crash the application, but
rather produce an error. This is called defensive programming.
Unfortunately, adding checks for values that should just not be
entered at all is not always practical: the checks cost cycles and
might cost more than it's worth. For example, some functions are
designed so that you may not give it a null pointer. In those
cases it's not sensible to pass it <code>NULL</code> just to see it
crash.
Since every experienced programmer add an <code>assert()</code> to
ensure that you get a proper failure for the debug builds when a
null pointer passed (you add asserts too, right?), you will in this
case instead have a controlled (early) crash in the debug build.
@subsection ErrorHandlingTests Error handling
This is testing that the errors your component is designed to give
actually are produced. For example, testing that trying to open a
non-existing file produces a sensible error code.
@subsection BadEnvironmentTests Environment
Sometimes, modules has to behave well even when the environment
fails to work correctly. Typical examples are when the computer is
out of dynamic memory or when the disk is full. You can emulate
this by replacing, e.g., <code>malloc()</code> with your own
version that will work for a while, but then fail. Some things are
worth to keep in mind here:
- Make sure to make the function fail deterministically, so that
you really can repeat the test.
- Make sure that it doesn't just fail immediately. The unit might
have checks for the first case, but might actually fail some time
in the near future.
@section UnitTest How to structure a unit test
In this section we will give some advice on how to structure the
unit tests to make the development run smoothly. The basic
structure of a test is:
- Plan
- Test
- Report
@subsection TestPlanning Plan the test
Planning the test means telling how many tests there are. In the
event that one of the tests causes a crash, it is then possible to
see that there are fewer tests than expected, and print a proper
error message.
To plan a test, use the @c plan() function in the following manner:
@code
int main(int argc, char *argv[])
{
plan(5);
.
.
.
}
@endcode
If you don't call the @c plan() function, the number of tests
executed will be printed at the end. This is intended to be used
while developing the unit and you are constantly adding tests. It
is not indented to be used after the unit has been released.
@subsection TestRunning Execute the test
To report the status of a test, the @c ok() function is used in the
following manner:
@code
int main(int argc, char *argv[])
{
plan(5);
ok(ducks == paddling_ducks,
"%d ducks did not paddle", ducks - paddling_ducks);
.
.
.
}
@endcode
This will print a test result line on the standard output in TAP
format, which allows TAP handling frameworks (like Test::Harness)
to parse the status of the test.
@subsection TestReport Report the result of the test
At the end, a complete test report should be written, with some
statistics. If the test returns EXIT_SUCCESS, all tests were
successful, otherwise at least one test failed.
To get a TAP compliant output and exit status, report the exit
status in the following manner:
@code
int main(int argc, char *argv[])
{
plan(5);
ok(ducks == paddling_ducks,
"%d ducks did not paddle", ducks - paddling_ducks);
.
.
.
return exit_status();
}
@endcode
@section DontDoThis Ways to not do unit testing
In this section, we'll go through some quite common ways to write
tests that are <em>not</em> a good idea.
@subsection BreadthFirstTests Doing breadth-first testing
If you're writing a library with several functions, don't test all
functions using size 1, then all functions using size 2, etc. If a
test for size 42 fails, you have no easy way of tracking down why
it failed.
It is better to concentrate on getting one function to work at a
time, which means that you test each function for all sizes that
you think is reasonable. Then you continue with the next function,
doing the same. This is usually also the way that a library is
developed (one function at a time) so stick to testing that is
appropriate for now the unit is developed.
@subsection JustToBeSafeTest Writing unnecessarily large tests
Don't write tests that use parameters in the range 1-1024 unless
you have a very good reason to believe that the component will
succeed for 562 but fail for 564 (the numbers picked are just
examples).
It is very common to write extensive tests "just to be safe."
Having a test suite with a lot of values might give you a warm
fuzzy feeling, but it doesn't really help you find the bugs. Good
tests fail; seriously, if you write a test that you expect to
succeed, you don't need to write it. If you think that it
<em>might</em> fail, <em>then</em> you should write it.
Don't take this as an excuse to avoid writing any tests at all
"since I make no mistakes" (when it comes to this, there are two
kinds of people: those who admit they make mistakes, and those who
don't); rather, this means that there is no reason to test that
using a buffer with size 100 works when you have a test for buffer
size 96.
The drawback is that the test suite takes longer to run, for little
or no benefit. It is acceptable to do a exhaustive test if it
doesn't take too long to run and it is quite common to do an
exhaustive test of a function for a small set of values.
Use your judgment to decide what is excessive: your milage may
vary.
*/
/**
@example simple.t.c
This is an simple example of how to write a test using the
library. The output of this program is:
@code
1..1
# Testing basic functions
ok 1 - Testing gcs()
@endcode
The basic structure is: plan the number of test points using the
plan() function, perform the test and write out the result of each
test point using the ok() function, print out a diagnostics message
using diag(), and report the result of the test by calling the
exit_status() function. Observe that this test does excessive
testing (see @ref JustToBeSafeTest), but the test point doesn't
take very long time.
*/
/**
@example todo.t.c
This example demonstrates how to use the <code>todo_start()</code>
and <code>todo_end()</code> function to mark a sequence of tests to
be done. Observe that the tests are assumed to fail: if any test
succeeds, it is considered a "bonus".
*/
/**
@example skip.t.c
This is an example of how the <code>SKIP_BLOCK_IF</code> can be
used to skip a predetermined number of tests. Observe that the
macro actually skips the following statement, but it's not sensible
to use anything than a block.
*/
/**
@example skip_all.t.c
Sometimes, you skip an entire test because it's testing a feature
that doesn't exist on the system that you're testing. To skip an
entire test, use the <code>skip_all()</code> function according to
this example.
*/

305
vendor/MDBC/unittest/mytap/tap.h vendored Normal file
View File

@ -0,0 +1,305 @@
/* Copyright (C) 2006 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; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA
Library for providing TAP support for testing C and C++ was written
by Mats Kindahl <mats@mysql.com>.
*/
#ifndef TAP_H
#define TAP_H
#include "ma_global.h"
/*
@defgroup MyTAP MySQL support for performing unit tests according to
the Test Anything Protocol (TAP).
*/
#define NO_PLAN (0)
/**
Data about test plan.
@ingroup MyTAP_Internal
@internal We are using the "typedef struct X { ... } X" idiom to
create class/struct X both in C and C++.
*/
typedef struct TEST_DATA {
/**
Number of tests that is planned to execute.
Can be zero (<code>NO_PLAN</code>) meaning that the plan string
will be printed at the end of test instead.
*/
int plan;
/** Number of last test that was done or skipped. */
int last;
/** Number of tests that failed. */
int failed;
/** Todo reason. */
char todo[128];
} TEST_DATA;
#ifdef __cplusplus
extern "C" {
#endif
/**
Defines whether "big" tests should be skipped.
This variable is set by plan() function unless MYTAP_CONFIG environment
variable is set to the string "big". It is supposed to be used as
@code
if (skip_big_tests) {
skip(1, "Big test skipped");
} else {
ok(life_universe_and_everything() == 42, "The answer is CORRECT");
}
@endcode
@see SKIP_BIG_TESTS
*/
extern int skip_big_tests;
/**
@defgroup MyTAP_API MyTAP API
MySQL support for performing unit tests according to TAP.
@{
*/
/**
Set number of tests that is planned to execute.
The function also accepts the predefined constant
<code>NO_PLAN</code>. If the function is not called, it is as if
it was called with <code>NO_PLAN</code>, i.e., the test plan will
be printed after all the test lines.
The plan() function will install signal handlers for all signals
that generate a core, so if you want to override these signals, do
it <em>after</em> you have called the plan() function.
It will also set skip_big_tests variable if MYTAP_CONFIG environment
variable is defined.
@see skip_big_tests
@param count The planned number of tests to run.
*/
void plan(int const count);
/**
Report test result as a TAP line.
Function used to write status of an individual test. Call this
function in the following manner:
@code
ok(ducks == paddling,
"%d ducks did not paddle", ducks - paddling);
@endcode
@param pass Zero if the test failed, non-zero if it passed.
@param fmt Format string in printf() format. NULL is allowed, in
which case nothing is printed.
*/
void ok(int const pass, char const *fmt, ...)
__attribute__((format(printf,2,3)));
/**
Skip a determined number of tests.
Function to print that <em>how_many</em> tests have been skipped.
The reason is printed for each skipped test. Observe that this
function does not do the actual skipping for you, it just prints
information that tests have been skipped. This function is not
usually used, but rather the macro @c SKIP_BLOCK_IF, which does the
skipping for you.
It shall be used in the following manner:
@code
if (ducks == 0) {
skip(2, "No ducks in the pond");
} else {
int i;
for (i = 0 ; i < 2 ; ++i)
ok(duck[i] == paddling, "is duck %d paddling?", i);
}
@endcode
@see SKIP_BLOCK_IF
@param how_many Number of tests that are to be skipped.
@param reason A reason for skipping the tests
*/
void skip(int how_many, char const *const reason, ...)
__attribute__((format(printf,2,3)));
/**
Helper macro to skip a block of code. The macro can be used to
simplify conditionally skipping a block of code. It is used in the
following manner:
@code
SKIP_BLOCK_IF(ducks == 0, 2, "No ducks in the pond")
{
int i;
for (i = 0 ; i < 2 ; ++i)
ok(duck[i] == paddling, "is duck %d paddling?", i);
}
@endcode
@see skip
*/
#define SKIP_BLOCK_IF(SKIP_IF_TRUE, COUNT, REASON) \
if (SKIP_IF_TRUE) skip((COUNT),(REASON)); else
/**
Helper macro to skip a group of "big" tests. It is used in the following
manner:
@code
SKIP_BIG_TESTS(1)
{
ok(life_universe_and_everything() == 42, "The answer is CORRECT");
}
@endcode
@see skip_big_tests
*/
#define SKIP_BIG_TESTS(COUNT) \
if (skip_big_tests) skip((COUNT), "big test"); else
/**
Print a diagnostics message.
@param fmt Diagnostics message in printf() format.
*/
void diag(char const *fmt, ...)
__attribute__((format(printf,1,2)));
/**
Print a bail out message.
A bail out message can be issued when no further testing can be
done, e.g., when there are missing dependencies.
The test will exit with status 255. This function does not return.
@code
BAIL_OUT("Lost connection to server %s", server_name);
@endcode
@note A bail out message is printed if a signal that generates a
core is raised.
@param fmt Bail out message in printf() format.
*/
void BAIL_OUT(char const *fmt, ...)
__attribute__((noreturn, format(printf,1,2)));
/**
Print summary report and return exit status.
This function will print a summary report of how many tests passed,
how many were skipped, and how many remains to do. The function
should be called after all tests are executed in the following
manner:
@code
return exit_status();
@endcode
@returns @c EXIT_SUCCESS if all tests passed, @c EXIT_FAILURE if
one or more tests failed.
*/
int exit_status(void);
/**
Skip entire test suite.
To skip the entire test suite, use this function. It will
automatically call exit(), so there is no need to have checks
around it.
*/
void skip_all(char const *reason, ...)
__attribute__((noreturn, format(printf, 1, 2)));
/**
Start section of tests that are not yet ready.
To start a section of tests that are not ready and are expected to
fail, use this function and todo_end() in the following manner:
@code
todo_start("Not ready yet");
ok(is_rocketeering(duck), "Rocket-propelled ducks");
ok(is_kamikaze(duck), "Kamikaze ducks");
todo_end();
@endcode
@see todo_end
@note
It is not possible to nest todo sections.
@param message Message that will be printed before the todo tests.
*/
void todo_start(char const *message, ...)
__attribute__((format(printf, 1, 2)));
/**
End a section of tests that are not yet ready.
*/
void todo_end();
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* TAP_H */