I created a MySQL database, with some stored procedures. Using MySQL Workbench the SP forks fine, and now I need to launch them using a c program.
I created the program, which connect successfully to my db, and I'm able to launch procedures which not requires parameters.
To launch more complex procedure I need to use the prepare statement in c: in particular, I want to call the procedure esame_cancella(IN code CHAR(5)) which deletes a selected row of the table 'esame'.
int status;
MYSQL_RES *result;
MYSQL_ROW row;
MYSQL_FIELD *field;
MYSQL_RES *rs_metadata;
MYSQL_STMT *stmt;
MYSQL_BIND ps_params[6];
unsigned long length[6];
char cod[64];
printf("Codice: ");
scanf ("%s",cod);
length[0] = strlen(cod);
stmt = mysql_stmt_init(conn);
if (stmt == NULL) {
printf("Could not initialize statement\n");
exit(1);
}
status = mysql_stmt_prepare(stmt, "call esame_cancella(?) ", 64);
test_stmt_error(stmt, status); //line which gives me the syntax error
memset(ps_params, 0, sizeof(ps_params));
ps_params[0].buffer_type = MYSQL_TYPE_VAR_STRING;
ps_params[0].buffer = cod;
ps_params[0].buffer_length = 64;
ps_params[0].length = &length[0];
ps_params[0].is_null = 0;
// bind parameters
status = mysql_stmt_bind_param(stmt, ps_params); //muore qui
test_stmt_error(stmt, status);
// Run the stored procedure
status = mysql_stmt_execute(stmt);
test_stmt_error(stmt, status);
}
I use test_stmt_error to see MySQL log calling procedures.
static void test_stmt_error(MYSQL_STMT * stmt, int status)
{
if (status) {
fprintf(stderr, "Error: %s (errno: %d)\n",
mysql_stmt_error(stmt), mysql_stmt_errno(stmt));
exit(1);
}
}
when I compile, and launch my program, I have the following log:
Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 (errno: 1064)
Any help?
It looks like the string length being passed to mysql_stmt_prepare is wrong - try changing the 64 to 24.
Or better yet, try something like:
const char sql_sp[] = "call esame_cancella(?) ";
...
status = mysql_stmt_prepare(stmt, sql_sp, sizeof(sql_sp));
Related
I'm coding a setup for my "game" server and I use MySQL for database. I getting an error when I create the database + table and the columns. I tested the Mysql code in phpmyadmin and it worked.
Here's a sample of my code: `
int area;
char user[100];
char pass[100];
char ip[200];
char tentativaspm;
void mysqlsetup(){
MYSQL *CON = mysql_init(NULL);
if (CON == NULL)
{
fprintf(stderr, "%s\n", mysql_error(CON));
exit(1);
}
if (mysql_real_connect(CON, ip, user, pass,
NULL, 0, NULL, 0) == NULL)
{
fprintf(stderr, "%s\n", mysql_error(CON));
mysql_close(CON);
sleep(2);
userepassmysql();
}
printf("Conecao establecida.\n");
if(mysql_query(CON, "CREATE DATABASE place;")){
fprintf(stderr, "%s\n", mysql_error(CON));
mysql_close(CON);
exit(1);
}
if(mysql_query(CON, "USE place; CREATE TABLE grid (pixelID int,color int);"){
fprintf(stderr, "%s\n", mysql_error(CON));
mysql_close(CON);
exit(1);
}
And I get this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'USE grid CREATE TABLE grid (pixelID int(11) NOT NULL,color int(11) NOT N' at line 1
By default the mysql_query c function doesn't support multiple SQL statements.
But you can combine the two queries
USE [database];
CREATE TABLE grid (pixelID int,color int)
into the oneliner
CREATE TABLE [database].grid (pixelID INT, color INT)
Note replace [database] with the correct database name.
Solution one
Using the oneliner
if(mysql_query(CON, "CREATE TABLE place.grid (pixelID int,color int);"){
Solution two
Use the function mysql_set_server_option() function to enable multiple SQL statements.
mysql_set_server_option(connection, MYSQL_OPTION_MULTI_STATEMENTS_ON);
I work on a C tool, in which I need to manipulate and query process-internal data intensively.
Hence, I've decided to use the MySQL C API on Embedded mode, so I can have an embedded DB for each running process of my tool, and use all the SQL features on it.
All the MySQL C API tutorials I've found over the web, deal with connecting to a running server, which is not my case.
There are some examples for working with Embedded mode in Oracle's MySQL website, but they are not simple, and it's hard to make them work.
Q: Can someone please point me or write me a short example for initiating a DB using MySQL C API on Embedded mode?
Thanks!
After a lot of tries, finally answering to myself and sharing it with you:
Create a central data directory that would be used for storing DBs. In this example, I'll use /tmp/mysql_embedded_data
> mkdir /tmp/mysql_embedded_data
Create a C file, as in the following example:
#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);
}
Compile your file (I assume in this example that my C filename is /tmp/mysql_try.c)
gcc /tmp/mysql_try.c -o /tmp/mysql_try -lz `mysql_config --include --libmysqld-libs`
Run your compiled program:
> /tmp/mysql_try
When your program returnes, ensure that the DB creation succeeded. We named our sample DB aNewDatabase, so we'll check if it now has a directory inside the data directory we created -> We'll check if the directory /tmp/mysql_embedded_data/aNewDatabase was created:
> ls /tmp/mysql_embedded_data/aNewDatabase
db.opt
Enjoy!
Does anyone know why the following would cause a segmentation fault when run?
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
printf("MySQL client version : %s\n", mysql_get_client_info());
MYSQL *conn=NULL;
mysql_init(conn);
char *server = "localhost";
char *user = "root";
char *password = "pass";
char *database = "weather";
char *table ="room_temp";
char *tst_qry="INSERT INTO `weather`.`room_temp` (`idx`, `date`, `temperature`) VALUES (NULL, CURRENT_TIMESTAMP, '10')";
mysql_real_connect(conn, server, user, password, database, 0, NULL, 0);
}
I complied as follows
gcc -o mysql $(mysql_config --cflags) mysql.c $(mysql_config --libs)
The output was as follows,
MySQL client version : 5.5.31
Segmentation fault
Please help!
The allocated new object isn't stored in your code. Hence you are passing the NULL to mysql_real_connect().
Change this line:
mysql_init(conn);
to:
conn = mysql_init(conn);
or rather directly:
conn = mysql_init(NULL);
You're passing a NULL-pointer to mysql_real_connect. According to the documentation mysql_init returns an initialized MYSQL object (when passed a NULL-pointer). Change your code either to this to use the return value:
conn = mysql_init(conn);
or this, to have mysql_init fill the object:
MYSQL conn; /* note that this isn't a pointer */
mysql_init(&conn);
...
mysql_real_connect(&conn, ...);
In an XMLRPC server that I'm working on (based off xmlrpc-c) the threads may want to make a MySQL connection to retrieve some data, using the following function:
Distribution getEntitySetFromMysql( int id ) {
Distribution result;
try {
sql::Driver *driver = get_driver_instance();
sql::Connection *con = driver->connect( (std::string)DBHOST, (std::string)USER, (std::string)PASSWORD);
con->setSchema( (std::string)DATABASE );
sql::Statement *stmt = con->createStatement();
std::stringstream query;
query << "SELECT concept_id, weight FROM entity_set_lines WHERE entity_set_id = " << id;
sql::ResultSet *res = stmt->executeQuery ( query.str() );
while (res->next()) {
result[ res->getInt("concept_id") ] = res->getDouble("weight");
}
delete res;
delete stmt;
con->close();
delete con;
} catch (sql::SQLException &e) {
std::cout << "ERROR: SQLException in " << __FILE__;
std::cout << " (" << __func__<< ") on line " << __LINE__ << std::endl;
std::cout << "ERROR: " << e.what();
std::cout << " (MySQL error code: " << e.getErrorCode();
std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;
if (e.getErrorCode() == 1047) {
std::cout << "\nYour server does not seem to support Prepared Statements at all. ";
std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
}
} catch (std::runtime_error &e) {
std::cout << "ERROR: runtime_error in " << __FILE__;
std::cout << " (" << __func__ << ") on line " << __LINE__ << std::endl;
std::cout << "ERROR: " << e.what() << std::endl;
}
return result;
}
All works fine, but after a thread runs this code and successfully returns its result, the thread remains hanging and does not exit. What is wrong with this approach? How fundamentaly wrong is this? Is the MySQL connector thread safe?
While Googling around for a solutions, I came across mentions of sql::Driver::threadInit() and sql::Driver::threadEnd(). However, as I was on version 1.0.5 of the C++ Connector, these functions were not available to me. Adding a driver->threadInit(); after getting a driver instance and driver->threadEnd(); at the end of my function, this problem was resolved.
The following is the mention of this thread init and end functionality in MySQL's 1.1.0 change history:
Added Driver::threadInit() and Driver::threadEnd() methods. Every
thread of a threaded client must call Driver::threadInit() at the very
start of the thread before it does anything else with Connector/C++
and every thread must call Driver::threadEnd() when it finishes. You
can find an example demonstrating the use in examples/pthreads.cpp. It
is strongly discouraged to share connections between threads. It is
theoretically possible, if you set certain (undocumented) mutexes, but
it is not supported at all. Use one connection per thread. Do not have
two threads using the same connection at the same time. Please check
the C API notes on threading on the MySQL manual. Connector/C++ wraps
the C API. (Lawrin, Andrey, Ulf)
TL;DR: If you come across this problem, make sure that your version of the C++ MySQL Connector is >= 1.1.0 and use the sql::Driver::threadInit() and sql::Driver::threadEnd() methods to surround your connection code.
Two thoughts:
libmysql isn't fully thread safe.
the way your code is structured you will leak memory if an exception occurs. you might be better served by either declaring your variables outside the try/catch and using a finally (or local equivalent) to ensure proper cleanup or using smart pointers (if available).
Since you don't show any of the calling or surrounding code it's hard to tell what's actually going on. Do you check the exit code of the thread when it's supposedly done? Can you attach it in a debugger to see what it's doing instead of closing?
Actually :
DO NOT USE : sql::Driver::threadInit() nor sql::Driver::threadEnd()
BECAUSE : you are already using try()
YOU FORGOT :
res->close();
stmt->close();
con->close();
delete res;
delete stmt;
delete con;
EXAMPLE :
int connection_and_query_func()
{
/*connection and query variables*/
sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
int err_exception_getErrorCode=0;
/*results variables*/
int my_int_from_column_1 = 0;
double my_double_from_column_2 = 0;
....
std:string my_string_from_column_p = "";
try
{
/* Create a connection */
driver = get_driver_instance();
con = driver->connect("address_name", "user_name", "password");
/* Connect to the MySQL database */
con->setSchema("schema_name");
/* Execute MySQL Query*/
stmt = con->createStatement();
res = stmt->executeQuery("your query statement here");
/* Read MySQL Query results per column*/
my_int_from_column_1 = res->getInt(1);
my_double_from_column_2 = res->getDouble(2);
....
my_string_from_column_p = res->getString(p);
/* Close MySQL Connection*/
res->close();
stmt->close();
con->close();
delete res;
delete stmt;
delete con;
};
/* Get last error*/
catch (sql::SQLException &exception)
{
err_exception_getErrorCode = exception.getErrorCode();
};
return(0);
};
CONCLUSION : this can be executed as many times as you want. The function example (connection_and_query_func()) will close MySQL connection properly after it is done - without adding up processes to your MySQL server!!!
FURTHERMORE : read the official manual https://docs.oracle.com/cd/E17952_01/connector-cpp-en/connector-cpp-en.pdf
ALTERNATIVE : if you cannot close properly your connection and query from your program/function side (thus adding up processes to your MySQL server) consider the 2 following options:
1/ set all MySQL timeout parameters to 10 sec. or less (for instance);
2/ write a script that SHOW PROCESSLIST and delete processes that are in SLEEP for too long.
Cheers.
hello all i have write a c program which connects to a mysql server and executes a sql query from a text file which has only one query.
#include <mysql.h>
#include <stdio.h>
main() {
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;
char *server = "127.0.0.1";
char *user = "root";
char *password = "PASSWORD"; /* set me first */
char *database = "har";
conn = mysql_init(NULL);
char ch, file_name[25];
char *ch1;
FILE *fp;
printf("Enter the name of file you wish to see ");
gets(file_name);
fp = fopen(file_name,"r"); // read mode
if( fp == NULL )
{
perror("Error while opening the file.\n");
exit(0);
}
while( ( ch = fgetc(fp) ) != EOF )
printf("%c",ch);
ch1=ch;
/* Connect to database */
if (!mysql_real_connect(conn, server,
NULL , NULL, database, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(0);
}
printf("%c",ch);
/* send SQL query */
if (mysql_query(conn, ch1)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(0);
}
res = mysql_use_result(conn);
/* output table name */
printf("MySQL Tables in mysql database:\n");
while ((row = mysql_fetch_row(res)) != NULL)
printf("%s \n", row[0]);
/* close connection */
mysql_free_result(res);
mysql_close(conn);
fclose(fp);
}
i am unable to understand where i have gone wrong....
thanks in advance...
This is the line causing problem:
ch1=ch;
ch1 is a pointer to a character, whereas ch is a character.
Do you intend to store the bytes read from fp in a char array pointed by ch1? What you are doing is, every time in the while loop you are reading a character using fgetc storing it in ch and printing it.
Then, when while loop gets over, you are assigning a char to a char pointer. I am not sure what you are trying to do with this. But this definitely causes the problem.
You're going wrong in a lot of ways:
You don't declare the return type or arguments for main.
You're using gets. Never ever use gets, don't even think about. Use fgets instead.
fgetc returns an int, not a char so your ch should be an int. You won't be able to recognize EOF until you fix this.
You're declaring char ch and char *ch1 but assigning ch to ch1. That's where the error in your title is coming from.
Your code appears to be trying feed your SQL to MySQL one byte at a time and that's not going to do anything useful. I think you're meaning to use fgets to read the SQL file one line a time so that you can feed each line to MySQL as a single SQL statement.
You should spend some time reading about your compiler's warning switches