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:
67
vendor/MDBC/unittest/libmariadb/CMakeLists.txt
vendored
Normal file
67
vendor/MDBC/unittest/libmariadb/CMakeLists.txt
vendored
Normal 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
271
vendor/MDBC/unittest/libmariadb/async.c
vendored
Normal 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());
|
||||
}
|
843
vendor/MDBC/unittest/libmariadb/basic-t.c
vendored
Normal file
843
vendor/MDBC/unittest/libmariadb/basic-t.c
vendored
Normal 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
1100
vendor/MDBC/unittest/libmariadb/bulk1.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
846
vendor/MDBC/unittest/libmariadb/charset.c
vendored
Normal file
846
vendor/MDBC/unittest/libmariadb/charset.c
vendored
Normal 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());
|
||||
}
|
53
vendor/MDBC/unittest/libmariadb/conc336.c
vendored
Normal file
53
vendor/MDBC/unittest/libmariadb/conc336.c
vendored
Normal 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;
|
||||
|
||||
}
|
1972
vendor/MDBC/unittest/libmariadb/connection.c
vendored
Normal file
1972
vendor/MDBC/unittest/libmariadb/connection.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1841
vendor/MDBC/unittest/libmariadb/cursor.c
vendored
Normal file
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
100
vendor/MDBC/unittest/libmariadb/data.csv
vendored
Normal 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
|
|
323
vendor/MDBC/unittest/libmariadb/dyncol.c
vendored
Normal file
323
vendor/MDBC/unittest/libmariadb/dyncol.c
vendored
Normal 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
290
vendor/MDBC/unittest/libmariadb/errors.c
vendored
Normal 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());
|
||||
}
|
249
vendor/MDBC/unittest/libmariadb/features-10_2.c
vendored
Normal file
249
vendor/MDBC/unittest/libmariadb/features-10_2.c
vendored
Normal 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, ¶m_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, ¶m_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, ¶m_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, ¶m_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, ¶m_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
1003
vendor/MDBC/unittest/libmariadb/fetch.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4
vendor/MDBC/unittest/libmariadb/fingerprint.list.in
vendored
Normal file
4
vendor/MDBC/unittest/libmariadb/fingerprint.list.in
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
86DD6D764C0CA47C5014E1E7802674BFDB674ED3
|
||||
@SSL_CERT_FINGER_PRINT@
|
||||
73F1FEC1FE041473563BFF2D624B88F6CFCFE626
|
||||
|
742
vendor/MDBC/unittest/libmariadb/getopt.c
vendored
Normal file
742
vendor/MDBC/unittest/libmariadb/getopt.c
vendored
Normal 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
217
vendor/MDBC/unittest/libmariadb/logs.c
vendored
Normal 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());
|
||||
}
|
741
vendor/MDBC/unittest/libmariadb/ma_getopt.c
vendored
Normal file
741
vendor/MDBC/unittest/libmariadb/ma_getopt.c
vendored
Normal 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 */
|
135
vendor/MDBC/unittest/libmariadb/ma_getopt.h
vendored
Normal file
135
vendor/MDBC/unittest/libmariadb/ma_getopt.h
vendored
Normal 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
1666
vendor/MDBC/unittest/libmariadb/misc.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
711
vendor/MDBC/unittest/libmariadb/my_test.h
vendored
Normal file
711
vendor/MDBC/unittest/libmariadb/my_test.h
vendored
Normal 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);
|
||||
}
|
||||
}
|
76
vendor/MDBC/unittest/libmariadb/performance.c
vendored
Normal file
76
vendor/MDBC/unittest/libmariadb/performance.c
vendored
Normal 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
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
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
511
vendor/MDBC/unittest/libmariadb/ps_new.c
vendored
Normal 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
1102
vendor/MDBC/unittest/libmariadb/result.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
74
vendor/MDBC/unittest/libmariadb/rpl_api.c
vendored
Normal file
74
vendor/MDBC/unittest/libmariadb/rpl_api.c
vendored
Normal 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
91
vendor/MDBC/unittest/libmariadb/sp.c
vendored
Normal 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
1424
vendor/MDBC/unittest/libmariadb/ssl.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
164
vendor/MDBC/unittest/libmariadb/t_aurora.c
vendored
Normal file
164
vendor/MDBC/unittest/libmariadb/t_aurora.c
vendored
Normal 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());
|
||||
}
|
72
vendor/MDBC/unittest/libmariadb/t_conc173.c
vendored
Normal file
72
vendor/MDBC/unittest/libmariadb/t_conc173.c
vendored
Normal 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
180
vendor/MDBC/unittest/libmariadb/thread.c
vendored
Normal 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
697
vendor/MDBC/unittest/libmariadb/view.c
vendored
Normal 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 *)¶ms[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 *)¶ms[i], "%d", i);
|
||||
my_bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
|
||||
my_bind[i].buffer = (char *)¶ms[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());
|
||||
}
|
19
vendor/MDBC/unittest/mytap/CMakeLists.txt
vendored
Normal file
19
vendor/MDBC/unittest/mytap/CMakeLists.txt
vendored
Normal 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
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
33
vendor/MDBC/unittest/mytap/t/basic-t.c
vendored
Normal 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
600
vendor/MDBC/unittest/mytap/tap.c
vendored
Normal 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
305
vendor/MDBC/unittest/mytap/tap.h
vendored
Normal 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 */
|
Reference in New Issue
Block a user