Embedded MariaDB C/C++ API - mysql

I'm trying to get an embedded MariaDB (i.e. not connecting to running server) setup going but I'm failing to get any of the examples I find to work.
The most recent example I have is from this post https://stackoverflow.com/a/24548826/400048
When the app runs it produces:
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
The docs https://mariadb.com/kb/en/library/embedded-mariadb-interface/ isn't much help on this.
For convenience the code from that StackOverflow post is:
#include <my_global.h>
#include <mysql.h>
int main(int argc, char **argv) {
static char *server_options[] = {
"mysql_test", // An unused string
"--datadir=/tmp/mysql_embedded_data", // Your data dir
NULL };
int num_elements = (sizeof(server_options) / sizeof(char *)) - 1;
static char *server_groups[] = { "libmysqld_server",
"libmysqld_client", NULL };
// Init MySQL lib and connection
mysql_library_init(num_elements, server_options, server_groups);
MYSQL *con = mysql_init(NULL);
if (con == NULL) {
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
mysql_options(con, MYSQL_READ_DEFAULT_GROUP, "libmysqld_client");
mysql_options(con, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);
// Connect to no host/port -> Embedded mode
if (mysql_real_connect(con, NULL, NULL, NULL, NULL, 0, NULL, 0) == NULL) {
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
// Create a sample empty DB, named "aNewDatabase"
if (mysql_query(con, "CREATE DATABASE aNewDatabase")) {
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
// Close connection
mysql_close(con);
exit(0);
}
I had a cursory look at https://github.com/MariaDB/server but didn't know where to really look...or in fact what I was looking for.
How does one go about getting an embedded mariadb going?
I'm running on Mac OS High Sierra, MariaDB was installed with brew install mariadb --with-embedded.
UPDATE:
I'm fairly certain I'm linking to the correct lib.
ls /usr/local/lib | grep maria
FIND_LIBRARY(mariadb mariadb)
MESSAGE(FATAL_ERROR "BOOM ${mariadb}")
Output of which is:
BOOM /usr/local/lib/libmariadb.dylib
UPDATE 2
I'm now linking to the following. Note that I started with just libmysqld and added libraries until all link errors went away. The trouble here is I may not have all the correct libs or versions.
TARGET_LINK_LIBRARIES(sql_fn /usr/local/lib/libmysqld.a)
TARGET_LINK_LIBRARIES(sql_fn /usr/local/opt/openssl/lib/libcrypto.a)
TARGET_LINK_LIBRARIES(sql_fn /usr/local/opt/openssl/lib/libssl.a)
TARGET_LINK_LIBRARIES(sql_fn /usr/local/opt/bzip2/lib/libbz2.a)
TARGET_LINK_LIBRARIES(sql_fn /usr/local/lib/liblz4.a)
TARGET_LINK_LIBRARIES(sql_fn /usr/local/opt/zlib/lib/libz.a)
TARGET_LINK_LIBRARIES(sql_fn /usr/local/opt/xz/lib/liblzma.a)
TARGET_LINK_LIBRARIES(sql_fn /usr/local/lib/libsnappy.a)
It now compiles but exits with code 6
Process finished with exit code 6
Looking at https://stackoverflow.com/a/7495907/400048 if it's points to the same thing/is still true then exit code 6 means EX_ILLEGAL_TABLE 6, unfortunately I don't know what table that would be. The mysql_test and datadir strings passed in are valid identifiers/path.

Ok first a little explanation about your example. The user is using gcc to compile and I can see you are using cmake.
First what does -lz and mysql_config --include --libmysqld-libs means. The first is link zlib to link zlib in cmake you can refer to this answer, but long story short:
find_package( ZLIB REQUIRED )
if ( ZLIB_FOUND )
include_directories( ${ZLIB_INCLUDE_DIRS} )
target_link_libraries( sql_fn ${ZLIB_LIBRARIES} )
endif( ZLIB_FOUND )
Then you need the mariaDB library and that is the second part. mysql_config --include --libmysqld-libs this means execute the command mysql_config --include --libmysqld-libs which will return a string with the link options so execute the command:
$mysql_config --include --libmysqld-libs
-I/usr/local/mysql/include
-L/usr/local/mysql/lib -lmysqld
And you should get an output like the one above. The -I is to look for headers in a given directory and the -L is to search a library in a directory, the -l is to link a given library it serves the same purpose as -lz only you are adding -lmysqld.
Well now that all is explained you need only include the -I -L and -l options with mysql however this is not such a standard library so you need to include directories and libraries through a script as explained in this anwer. So again long story short there is no bullet proof for this for example my library is in /usr/local/mysql/lib and yours is in /usr/local/lib. Since that is the case it will be easier to use the second method.
execute_process(COMMAND mysql_config --include
OUTPUT_VARIABLE MYSQL_INCLUDE)
execute_process(COMMAND mysql_config --libmysqld-libs
OUTPUT_VARIABLE MYSQL_LIBS)
target_compile_options(sql_fn PUBLIC ${MYSQL_INCLUDE})
target_link_libraries(sql_fn ${MYSQL_LIBS})
And that is all the required information you need. Now we are glad we have Cmake to make things easier for us don't we. ;)
Here is my CMakeLists.txt
cmake_minimum_required(VERSION 3.6)
project(embedded_mysql)
set(CMAKE_CXX_STANDARD 14)
set(SOURCE_FILES main.cpp)
add_executable(embedded_mysql ${SOURCE_FILES})
find_package( ZLIB REQUIRED )
if ( ZLIB_FOUND )
include_directories( ${ZLIB_INCLUDE_DIRS} )
target_link_libraries( embedded_mysql ${ZLIB_LIBRARIES} )
endif( ZLIB_FOUND )
execute_process(COMMAND mysql_config --include
OUTPUT_VARIABLE MYSQL_INCLUDE)
execute_process(COMMAND mysql_config --libmysqld-libs
OUTPUT_VARIABLE MYSQL_LIBS)
string(STRIP ${MYSQL_LIBS} MYSQL_LIBS)
target_compile_options(embedded_mysql PUBLIC ${MYSQL_INCLUDE})
target_link_libraries(embedded_mysql ${MYSQL_LIBS})
You can see the code in github here

Related

Github Action - Can't build gtest using ccache, mingw, cmake and ninja

I am using this workflow: cmake_build.yaml
Here is my toplevel CMakeLists.txt:
cmake_minimum_required(VERSION 3.15)
project(
container
VERSION 0.1.0
DESCRIPTION "An extension to the standard container library in c++"
HOMEPAGE_URL ""
LANGUAGES CXX
)
add_executable(${PROJECT_NAME} src/main.cpp)
set_target_properties(
${PROJECT_NAME}
PROPERTIES
LINKER_LANGUAGE CXX
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}"
)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
target_include_directories(
${PROJECT_NAME}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
install(
DIRECTORY
include/${PROJECT_NAME_LOWERCASE}
DESTINATION
include
)
enable_testing()
add_subdirectory(test)
and test/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(my_project)
# GoogleTest requires at least C++14
set(CMAKE_CXX_STANDARD 17)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
add_executable(
hello_test
hello_test.cc
)
target_link_libraries(
hello_test
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(hello_test)
I am using the example from gtest docs:
test/hello_test.cc:
#include <gtest/gtest.h>
TEST(HelloTest, BasicAssertions) {
// Expect two strings not to be equal.
EXPECT_STRNE("hello", "world");
// Expect equality.
EXPECT_EQ(7 * 6, 42);
}
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
It builds fine on Windows MSVC, Macos Clang, Linux GCC, but fails using Mingw GCC, here is error shown:
FAILED: test/hello_test.exe test/hello_test[1]_tests.cmake D:/a/tsst/tsst/build/test/hello_test[1]_tests.cmake
cmd.exe /C "cd . && C:\ProgramData\chocolatey\bin\g++.exe -O3 -DNDEBUG test/CMakeFiles/hello_test.dir/hello_test.cc.obj -o test\hello_test.exe -Wl,--out-implib,test\libhello_test.dll.a -Wl,--major-image-version,0,--minor-image-version,0 lib/libgtest_main.a lib/libgtest.a -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cmd.exe /C "cd /D D:\a\tsst\tsst\build\test && D:\a\tsst\tsst\cmake-3.24.3-windows-x86_64\bin\cmake.exe -D TEST_TARGET=hello_test -D TEST_EXECUTABLE=D:/a/tsst/tsst/build/test/hello_test.exe -D TEST_EXECUTOR= -D TEST_WORKING_DIR=D:/a/tsst/tsst/build/test -D TEST_EXTRA_ARGS= -D TEST_PROPERTIES= -D TEST_PREFIX= -D TEST_SUFFIX= -D TEST_FILTER= -D NO_PRETTY_TYPES=FALSE -D NO_PRETTY_VALUES=FALSE -D TEST_LIST=hello_test_TESTS -D CTEST_FILE=D:/a/tsst/tsst/build/test/hello_test[1]_tests.cmake -D TEST_DISCOVERY_TIMEOUT=5 -D TEST_XML_OUTPUT_DIR= -P D:/a/tsst/tsst/cmake-3.24.3-windows-x86_64/share/cmake-3.24/Modules/GoogleTestAddTests.cmake""
CMake Error at D:/a/tsst/tsst/cmake-3.24.3-windows-x86_64/share/cmake-3.24/Modules/GoogleTestAddTests.cmake:112 (message):
Error running test executable.
Path: 'D:/a/tsst/tsst/build/test/hello_test.exe'
Result: Exit code 0xc0000139
Output:
Call Stack (most recent call first):
D:/a/tsst/tsst/cmake-3.24.3-windows-x86_64/share/cmake-3.24/Modules/GoogleTestAddTests.cmake:225 (gtest_discover_tests_impl)
ninja: build stopped: subcommand failed.
Build works fine without building gtest, and it fails when building test executable with gtest

error while connecting mariadb with c : undefined reference to `mysql_init#4'

I am trying to connect to mariadb database using c program. Initially it was showing error for #include <mysql.h> as no such file or directory.
But after including directory name, that problem is solved now, but it is showing another error.
Following is the code I was trying to run:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// #include "C:/Program Files/MariaDB 10.11/include/mysql/my_global.h"
#include "mysql/mysql.h"
int main (int argc, char* argv[])
{
// Initialize Connection
MYSQL *conn;
if (!(conn = mysql_init(0)))
{
fprintf(stderr, "unable to initialize connection struct\n");
exit(1);
}
// Connect to the database
if (!mysql_real_connect(
conn, // Connection
"mariadb.example.net", // Host
"db_user", // User account
"db_user_password", // User password
"test", // Default database
3306, // Port number
NULL, // Path to socket file
0 // Additional options
));
{
// Report the failed-connection error & close the handle
fprintf(stderr, "Error connecting to Server: %s\n", mysql_error(conn));
mysql_close(conn);
exit(1);
}
// Use the Connection
// ...
// Close the Connection
mysql_close(conn);
return 0;
}
I am getting following error in output:
PS C:\Dev\Win> gcc Db_con.c -o Db_con
C:\Users\hajos\AppData\Local\Temp\ccGZ2Rhz.o:Db_con.c:(.text+0x1e): undefined reference to `mysql_init#4'
C:\Users\hajos\AppData\Local\Temp\ccGZ2Rhz.o:Db_con.c:(.text+0xa1): undefined reference to `mysql_real_connect#32'
C:\Users\hajos\AppData\Local\Temp\ccGZ2Rhz.o:Db_con.c:(.text+0xaf): undefined reference to `mysql_error#4'
C:\Users\hajos\AppData\Local\Temp\ccGZ2Rhz.o:Db_con.c:(.text+0xd9): undefined reference to `mysql_close#4'
collect2.exe: error: ld returned 1 exit status
Can anyone explain what is the problem and how to solve it?
You have to link against the MariaDB Connector/C libraries.
From MariaDB Connector/C documentation:
Linking your application against MariaDB Connector/C
Windows
For static linking the library libmariadb.lib is required, for dynamic linking use libmariadb.dll. Using the MSI installer, these libraries can be found in the lib directory of your MariaDB Connector/C installation.
Unless you use the experimental plugin remote_io (which requires the curl library) there are no dependencies to other libraries than the Windows system libraries.

"Can't connect ... through socket '/tmp/mysql.sock' " using C API mysql_real_connect() but /tmp/mysql.sock' exists

I'm running OS 11.1 Big Sur and updating an objective C program that uses the MySql C API (NOT the C Connector).
I CAN connect to local MySql server from the command line using
/usr/local/mysql/bin/mysql --user=root --password=aPassword
but when my software tries to connect through the C API using mysql_real_connect(mSQLPtr, theHost, theLogin, thePass, theDatabase, 0, NULL, 0); it fails with
Failed to connect to database: Error: Can't connect to local MySQL
server through socket '/tmp/mysql.sock' (1)
I've read heaps of posts to try and fix it e.g. stopping and starting the server, checking that /tmp/mysql.sock file does exist after starting the server (AND IT DOES EXIST), and adding a my.cnf to the /etc folder. It contains:
[mysqld]
socket=/tmp/mysql.sock
[client]
socket=/tmp/mysql.sock
Nothing has worked so far.
Can anyone offer any suggestions please.
Cheers
Jeff
#include <stdio.h>
#include <stdlib.h>
#include <mysql.h>
static char *host = "localhost";
static char *user = "user";
static char *pass = "password";
static char *db = "mysql";
static char *socket = NULL;
unsigned int port = 3306;
unsigned int flags = 0;
/*
* brew install mysql-client
* export PATH=/usr/local/opt/mysql-client/bin:$PATH
* brew install mysql-connector-c++ (optional)
* gcc -o main $(mysql_config --cflags) main.c $(mysql_config --libs) -L/usr/local/opt/openssl/lib
*
* -L/usr/local/opt/openssl/lib is required if you get ld: library not found for -lssl error
*/
int main(int argc, char *argv[]) {
MYSQL *con = mysql_init(NULL);
if (!mysql_real_connect(con, host, user, pass, db, port, socket, flags)) {
fprintf(stderr, "Error %s (%d)", mysql_error(con), mysql_errno(con));
exit(1);
}
printf("Connected\n");
return EXIT_SUCCESS;
}

cannot link to static mysqlclient library, though shared library works

I have a sample program to familiarize myself with mysqlclient APIs. However when I compile and link it to the mysqlclient library statically (.a file), the linker complains it cannot find the file, although it exists in my path. Linking to the shared library (.dylib file on my Mac) works.
Please help me get my head around this behaviour. Much appreciated!
Here's my driver program client.c that calls mysqlclient library.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <mysql.h>
int main(int argc, char **argv)
{
MYSQL *mysql = NULL;
if (mysql_library_init(argc, argv, NULL)) {
fprintf(stderr, "could not initialize MySQL client library\n");
exit(1);
}
mysql = mysql_init(mysql);
if (!mysql) {
puts("Init faild, out of memory?");
return EXIT_FAILURE;
}
if (!mysql_real_connect(mysql, /* MYSQL structure to use */
NULL, /* server hostname or IP address */
NULL, /* mysql user */
NULL, /* password */
NULL, /* default database to use, NULL for none */
0, /* port number, 0 for default */
NULL, /* socket file or named pipe name */
CLIENT_FOUND_ROWS /* connection flags */ )) {
puts("Connect failed\n");
} else {
const char *query = "SELECT VERSION()";
if (mysql_real_query(mysql, query, strlen(query))) {
printf("Query failed: %s\n", mysql_error(mysql));
} else {
puts("Query OK");
}
}
mysql_close(mysql);
mysql_library_end();
return EXIT_SUCCESS;
}
Here's how I compile it
gcc -I /usr/local/Cellar/mysql/8.0.16/include/mysql client.c -L /usr/local/Cellar/mysql/8.0.16/lib/ -l mysqlclient.a
ld: library not found for -lmysqlclient.a
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Compiling without the .a succeeds, as it links to the shared library, not static one.
Lastly, here's my library files:
ls /usr/local/Cellar/mysql/8.0.16/lib/libmysqlclient*
/usr/local/Cellar/mysql/8.0.16/lib/libmysqlclient.21.dylib /usr/local/Cellar/mysql/8.0.16/lib/libmysqlclient.a /usr/local/Cellar/mysql/8.0.16/lib/libmysqlclient.dylib
This argument:
-l mysqlclient.a
causes the linker to look for a file named libmysqlclient.a.a. Instead, you want something like:
gcc -I /usr/local/Cellar/mysql/8.0.16/include/mysql client.c /usr/local/Cellar/mysql/8.0.16/lib/mysqlclient.a
-lmysqlclient should work. The extension .a does not need.
When you want to use static link, --static should be used.
You may also need to link other libraries
gcc client.c -o client --static -lmysqlclient -lssl -lcrypto -ldl -lpthread

Using mysql in c programming

I installed ubuntu on a virtual machine. There, I installed mysql server sudo apt-get install mysql-server .This worked, because I could acces mysql-u root -p password
After that, I did : sudo apt-get install libmysqlclient-dev
#include <my_global.h>
#include <mysql.h>
int main(int argc, char **argv)
{
printf("MySQL client version: %s\n", mysql_get_client_info());
exit(0);
}
When I compile this with
gcc version.c -o version `mysql_config --cflags --libs`
it works.
But when I compile this one from below
gcc createdb.c -o createdb -std=c99 `mysql_config --cflags --libs`
I get some errors.
#include <my_global.h>
#include <mysql.h>
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
if (mysql_real_connect(con, "localhost", "root", "root_pswd",
NULL, 0, NULL, 0) == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
if (mysql_query(con, "CREATE DATABASE testdb"))
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
mysql_close(con);
exit(0);
}
Errors:
"Usage:: No such file or directory
[OPTIONS]: No such file or directory
Options:: No such file or directory
[-I/usr/include/mysql: No such file or directory
[-L/user/lib/x86_64-linux-gnu: No such file or directory
.
.
.
unrecognized command line option '--cflags'
unrecognized command line option '--libs'
.
.
unrecognized command line option '--socket'
unrecognized command line option '--port' "
Can someone explain me what I did wrong,and how to fix it?
I just want to get some data from tables in a C program.
I suspect you actually ran
gcc createdb.c -o createdb -std=c99 `mysql_config` --cflags --libs
rather than
gcc createdb.c -o createdb -std=c99 `mysql_config --cflags --libs`
That’s not going to work; mysql_config, if it doesn’t get any arguments, is going to print out a bunch of usage instructions, which will be passed to gcc, and then you’ll follow that with --cflags --libs, which gcc also doesn’t understand. gcc is severely confused and complains.
If you make sure those arguments get to mysql_config rather than gcc, everyone will be happy.