I'm using a mysql snippet that connects to my mysql database (locally) in ANSI C. Everything is working perfectly, but I've been trying to create a function that connects to my database and inserts a new record based on some variables. I'm using sprintf to snag those variables and piece them together to form my SQL query.
Problem
Once I have my variables and my SQL ready, I send it over to mysql_query. Unfortunately, this does not work as expected, the program crashes and reports a buffer overflow.
Here are pieces of the overall function that may help explain the problem.
#include <mysql.h>
#include <string.h>
#include <stdio.h>
char *table = "test_table"; // table is called test_table
char *column = "value"; // column is called value
char *value = "working"; // what value we are inserting
char *query; // what we are sending to mysql_query
sprintf(query, "INSERT INTO %s (%s) VALUES ('%s')", table, column, value);
if (mysql_query(conn, query)) {
fprintf(stderr, "%s\n", mysql_error(conn));
return;
}
Purpose
The purpose of the overall function is so I don't have to keep rewriting SQL insert or update statements in my program. I want to call to one function and pass a few parameters that identify the table, columns and the values of said columns.
Any help would be most appreciated. I'm a bit rusty in C these days.
Question
Why is mysql_query not able to send the string?
Changes
This worked based on the comments.
const char *query[MAX_STRING_LENGTH];
sprintf((char *)query, "INSERT INTO %s (%s) VALUES ('%s')", table, column, value);
if (mysql_query(conn, (const char *)query)) {
You have no backing storage for query.
It's either set to NULL or some indeterminate value, depending on its storage duration, neither of which will end well :-)
Quick fix is to change it to
char query[1000];
though any coder worth their salary would also check to ensure buffer overflow didn't occur.
Related
I'm a beginner in C and mysql programing.For some days now I am trying to write float and integer values that i get from sensors to a database in mySQL.So far i'm just getting an error "too many arguments to function ‘mysql_query’" and " expected ‘const char *’".Below is my simple code.
int main()
{
int var1 = 1;
float var2 = 5.1;
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;
conn = mysql_init(NULL);
if (!mysql_real_connect(conn, host, user, pass, dbname,port, unix_socket, flag))
{
fprintf(stderr, "\nError: %s [%d]\n",mysql_error(conn),mysql_errno(conn));
exit(1);
}
printf("Connection successful!\n");
mysql_query(conn,"INSERT INTO variables (var1) VALUE ('%d');",var1);
mysql_query(conn, mysql_query );
}
It's a nice idea, but mysql_query doesn't work with variable arguments.
You need to store the query in a buffer:
char buff[1024];
snprintf(buff, sizeof buff, "INSERT INTO variables (var1) VALUES ('%d');",var1);
and then you can call mysql_query with this buffer:
mysql_query(conn, buff);
EDIT:
As pointed out by #PaulOgilvie: Notice VALUES instead of VALUE in the query.
You should use a prepared statement, which would also take care of the types and all that (assuming conn is a valid connection object)
MYSQL_STMT *stmt;
MYSQL_BIND params[1];
const char *query;
// This is necessary or the program will crash
memset(params, 0, sizeof(params));
query = "INSERT INTO variables (var1) VALUES (?)";
stmt = mysql_stmt_init(conn);
params[0].buffer = &var1;
params[0].buffer_type = MYSQL_TYPE_LONG;
if (stmt == NULL)
exit(1); // Ideally handle the error and solve the problem
// but for simplicity ...
if (mysql_stmt_prepare(stmt, query, strlen(query)) != 0)
exit(1);
if (mysql_stmt_bind_param(stmt, params) != 0)
exit(1);
if (mysql_stmt_execute(stmt) != 0) {
// Ideally print mysql's error
fprintf(stderr, "an error occurred\n");
}
mysql_stmt_close(stmt);
This is the good safe way to do this, and also you can reuse the prepared statement as many times as you want and they promise it will be faster and more efficient because the query is prepared so the execution plan is known and you don't need to use the snprintf() which by the way should be checked for errors and also, you should check if the query did fit into the target array, read the documentation for that.
Also, you don't need to worry about escaping strings or anything. It will all be handled transparently for you. As long as you use the correct type and of course, specify the length of strings.
Note that you can bind parameters and results too in SELECT queries.
Are you sure you don't need "VALUES" here instead of "VALUE":
mysql_query(conn,"INSERT INTO variables (var1) VALUE ('%d');",var1);
I have two problems with the MySQL C API. How do I get variable to be added to the table when I do the mysql_query() and how do I get the table show decimals?
Here is my code:
void insertDataToTable(MYSQL* con, float temp, int k)
{
mysql_query(con, "INSERT INTO Weatherstation VALUES(#k,'Temperature:', #temp)");
}
Thank you!
Try this
void insertDataToTable(MYSQL* con, float temp, int k)
{
char query[255] ;
sprintf( query, "INSERT INTO Weatherstation VALUES(%ld,'Temperature:', %d)", temp, k );
mysql_query(con, query );
}
MySQL does not support host variables that well, the previous answer shows the correct approach in building the query into a string and then using mysql_query(someconnection, string).
What is absolutely shocking is that this is not documented as much as it should be. When I had to learn this I had 30 years of DB2 and C, and I had to get this from GitHub after 2 hours of fruitless searching for "MySQL Host Variables".
You should also be aware of mysql_real_query if your query is not a conventional string and contains embedded nulls, it is passed the length of the string, but can also move a strlen() call off the server.
I'm writing C program to access database.
I recently switch from sqlite to mysql.
I'm not familiar with mysql c api, so I need help converting some code.
Below example is executing sql statement with parameter.
sqlite:
char *zSQL = sqlite3_mprintf("SELECT price FROM warehouse WHERE p_ID='%q'", input_value);
sqlite3_prepare_v2(handle,zSQL,-1,&stmt,0);
my attempt in mysql:
char zSQL[60] = {'\0'};
int n = 0;
n = sprintf(zSQL, "SELECT price FROM warehouse WHERE p_ID='%s'", input_value);
mysql_real_query(conn, zSQL, n);
Another example is parsing result of sql statement to variable
sqlite:
double price_value = 0;
if (sqlite3_step (stmt) == SQLITE_ROW) {
price_value = sqlite3_column_double (stmt, 0);
}
mysql:
MYSQL_ROW row;
while ((row = mysql_fetch_row(result)))
{
price_value = atof(row[0]);
}
While the code in mysql works for me, but I feel like I'm not utilizing the API enough.
Is there any function in mysql c api which has the same functionality as sqlite3_mprintf() and sqlite3_column_double() ?
Edit:
My attempt on mysql_real_escape_string():
ulong in_length = strlen(input_value);
char input_esc[(2 * in_length)+1];
mysql_real_escape_string(conn, input_esc, input_value, in_length);
char sql_stmnt[56] = {'\0'};
n = sprintf(zSQL, "SELECT price FROM warehouse WHERE p_ID='%s'", input_esc);
mysql_real_query(conn, sql_stmnt, n);
For your first exampe, the short answer is no, you have to do it yourself, see http://dev.mysql.com/doc/refman/5.5/en/mysql-real-escape-string.html
unsigned long mysql_real_escape_string(MYSQL *mysql, char *to, const char *from, unsigned long length)
The second one, yes, that's the way to go, with some additional check that row[0] is indeed of type double.
Alternatively, you can use the prepared statement API which works quite similar to the one in sqlite3. The key is you provide buffers of type MYSQL_BIND and then either bind the inputs to it, or have mysql binding output values there.
Prepared statement documentation: http://dev.mysql.com/doc/refman/5.5/en/c-api-prepared-statement-data-structures.html
I am using C MySQL API
int numr=mysql_num_rows(res);
It always returns zero, but in my table there are 4 rows are there. However, I am getting the correct fields count.
what is the problem? Am i doing anything wrong?
Just a guess:
If you use mysql_use_result(), mysql_num_rows() does not return the correct value until all the rows in the result set have been retrieved.
(from the mysql manual)
The only reason to receive a zero from mysql_num_rows(<variable_name>) is because the query did not return anything.
You haven't posted the query here that you run and then assign the result to your res variable so we can't check it.
But try running that exact query in your DB locally through whatever DB management software you use and see if you are able to achieve any results.
If the query is working fine, then it must be the way you're running the query in C, otherwise your query is broken.
Maybe post up a bit more of your code from C where you make the query and then run it.
Thanks
If you just want to count the number of rows in a table, say
SELECT COUNT(*) FROM table_name
You will get back a single column in a single row containing the answer.
I too have this problem. But I noticed that mysql.h defines mysql_num_rows() to return a "my_ulonglong". Also in the header file you will see that there is a type def for my_ulonglong. On my system size of a my_ulonglong is 8 bytes. When we try to print this out or cast this to an int we probably get the first four bytes which are zero. However I printed out the eight bytes at the address of my_ulonglong variable and it prints all zeros. So I think this function just doesn't work.
`my_ulonglong numOfRows;
MYSQL *resource;
MYSQL *connection;
mysql_query(connection,"SELECT * FROM channels");
resource = mysql_use_result(connection);
numChannels = mysql_num_rows(resource);
printf("Writing numChannels: %lu\n", numChannels); // returns 0
printf("Size of numChannels is %d.\n", sizeof(numChannels)); // returns 8
// however
unsigned char * tempChar;
tempChar = (unsigned char *) &numChannels;
for (i=0; i< (int) sizeof(numChannels); ++i) {
printf("%02x", (unsigned int) *tempChar++);
}
printf("\n");
// returned 0000000000000000 so I think its a bug.
//mysql.h typedef for my_ulonglong and function mysql_num_rows()
#ifndef _global_h
#if defined(NO_CLIENT_LONG_LONG)
typedef unsigned long my_ulonglong;
#elif defined (__WIN__)
typedef unsigned __int64 my_ulonglong;
#else
typedef unsigned long long my_ulonglong;
#endif
#endif
my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res);
`
I am using the MySQL C API to query the database and I have the results stored in MYSQL_ROW types. I am able to print the results to the console with
printf("%s", row[0]);
however, according to the MySQL C API documentation, I cannot use them as null-terminated strings.
At the bottom of the function overview, they say I can "extract" the information with mysql_store_result() or mysql_use_result(). However, I am still confused as to how this is done.
Ideally, I want to use the results as a string so I can do stuff like strcmp, but otherwise I definitely need to use the information somehow with those two functions.
Can somebody show me an example of how to do this?
Basically, you call mysql_store_result() or mysql_use_result() to access the result set, the former loads all the rows into memory on the client side, the latter accesses rows one at a time from the server. If you use mysql_use_result(), you need to call mysql_fetch_row() to access each row until the function returns NULL. Each successful call to mysql_fetch_row() will return a MYSQL_ROW which you can use to access the individual field values.
Since the fields are not nul-terminated, you need to use mysql_fetch_lengths() to get the lengths of each of the fields so that you can copy them somewhere else via memcpy, etc.
Since the field values are not nul-terminated you will need to add your own NUL character when you make the copy if you want to use it as a string. Be aware that the field values may contain binary data, so if you do treat it as a string, functions that expect a C string will stop processing data if it encounters a nul-character in the data.
Here is an example from the documentation that should help you put all this together:
MYSQL_ROW row;
unsigned int num_fields;
unsigned int i;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
unsigned long *lengths;
lengths = mysql_fetch_lengths(result);
for(i = 0; i < num_fields; i++)
{
printf("[%.*s] ", (int) lengths[i],
row[i] ? row[i] : "NULL");
}
printf("\n");
}