I'm trying to build a C-program to add data to my MYSQL database and I would like to use variables within the SQL string. I want to insert UNIX time (epoch) in one column and the result from an energy meter into the other (double)
Even though it builds without errors or warnings I can't get it to insert the data into the table. Can someone give me a hint of where to look?
Thankful for all help I can get as I'm pretty much fumbling in the dark
Regards,
Mikael
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <mysql.h>
#include <my_global.h>
#include <stdlib.h> // For exit function
int loggingok; // Global var indicating logging on or off
double result = 323.234567; //Debug
double actual_time_sec;
void calculate_watts(void)
{
MYSQL *conn = mysql_init(NULL);
char *server = "localhost";
char *user = "root";
char *password = "password"; /* set me first */
char *database = "power";
char SQL_String[100];
char time_char[11];
char result_char[11];
time_t actual_time;
actual_time = time(0);
actual_time_sec = difftime(actual_time,0);
sprintf(time_char,"%g",actual_time_sec);
sprintf(result_char,"%g",result);
printf("Tid: %g\n",actual_time_sec); //Debug
printf("Resultat: %g\n", result); //Debug
strcpy(SQL_String, "INSERT INTO consumption(time,consumption) VALUES(");
strcat(SQL_String, time_char);
strcat(SQL_String, ",");
strcat(SQL_String, result_char);
strcat(SQL_String, ")");
printf("SQL: %s", SQL_String); //Debug
// SQL_String = "INSERT INTO consumption(time,consumption) VALUES('"+ actual_time_sec +"',"+ result +")";
if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1); }
if (mysql_query(conn, SQL_String)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1); }
}
int main (int argc, char *argv[])
{
printf(argv[1]); //Debug
if(strcmp(argv[1], "db")) {
loggingok=1;
printf("Efergy E2 Classic decode \n\n");
calculate_watts(); }
else {
loggingok=0; }
return 0;
}
here is a great example...
http://php.net/mysql_query. Note the usage of sprintf here. The 2nd and 3rd parameters work with the sprintf to place the data in these 2 parameters exactly where they are needed in the SQL statement.
$query = sprintf("SELECT firstname, lastname, address, age FROM friends
WHERE firstname='%s' AND lastname='%s'",
mysql_real_escape_string($firstname),
mysql_real_escape_string($lastname));
// Perform Query
$result = mysql_query($query);
// Check result
// This shows the actual query sent to MySQL, and the error. Useful for debugging.
if (!$result) {
$message = 'Invalid query: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $query;
die($message);
}
Please note the usage of if (!$result) this allows you to do a quick validation of if you have success or not. If an error is found the text resturned from mysql_error is placed in the message variable and then presented when the app dies.
Related
I'm starting with C and MySQL, I have created a database with some columns and I want to store two of them and use it in other parts of the code. In the example that I give i'm trying to store one value of "latitud" from de database in variable float lat, but it give me an error in the core. Do you know how can I solve this? Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>
#define HOST "localhost"
#define USER "victor"
#define PASS "tfg"
#define DATABASE "barcos"
int main (int argc, char *argv[]){
MYSQL *con;
MYSQL_ROW row;
MYSQL_RES *res;
con = mysql_init(NULL);
if (!mysql_real_connect(con, HOST, USER, PASS, DATABASE, 0, NULL, 0)){ // CONEXIÓN A LA BASE DE DATOS
fprintf(stderr, "%s\n", mysql_error(con));
return 1;
}
mysql_query(con, "SELECT latitud FROM BARCOS ");
res = mysql_store_result(con);
printf("latitud:\n");
while((row = mysql_fetch_row(res)) !=0)
printf("%s\n", row[0]);
float lat = row[0] ? atof(row[0]) : 0.0;
printf("%f", lat);
mysql_free_result(res);
mysql_close(con);
return 0;
}
What is res after
res = mysql_store_result(con); // res could be NULL, you do not check the result
Then you fetch all rows and print them
while((row = mysql_fetch_row(res)) !=0) // no braces, that means, ...
printf("%s\n", row[0]); // print only the first element from each row
but afterwards you call
//row is NULL here, because you exhausted the set in the loop before
float lat = row[0] ? atof(row[0]) : 0.0;
and you cannot dereference a NULL pointer.
From mysql_store_result:
Return Values
A pointer to a MYSQL_RES result structure with the results. NULL if the statement did not return a result set or an error occurred.
From mysql_fetch_row:
Return Values
A MYSQL_ROW structure for the next row, or NULL (either if there are no more rows or when an error occurred).
I've been tearing my hair out for a while on this one. The C code is called from a bash script, which loops through a command's output in a while loop and passes variables to the C script as args. It goes through a list and partitions data properly. I've been using the C MySQL api, and up until now everything has been relatively straight forward. It tries to run a SELECT(EXISTS) command to dictate whether to input a new row, or update an existing one.
I have typed the command into MySQL terminal and it works perfectly. I have even printf'd it and copied the command directly into the terminal. It works....
So why then, am I getting Syntax errors? I've tried escaping fields and input using backticks, single quotes and double quotes and I'm still getting this dumbounding error. I thought maybe it was something to do with the null space? But I'm at my witts end. Here's the code, any advice would be greatly appreciated :)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <mysql/mysql.h>
const int MAXLEN = 100;
/* Compile with:
gcc db.connect.c `mysql_config --libs` -O1
for the best results
*/
/* Function definitions for later */
void finish_with_error(MYSQL *con);
int send_query(MYSQL *con, char query[MAXLEN]);
/* If any SQL commands fail, return an error message */
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
/* Helper function to send queries to MySQL database */
int send_query(MYSQL *con, char query[MAXLEN])
{
if (mysql_query(con, query)) {
finish_with_error(con);
}
return 0;
}
int main(int argc, char ** argv)
{
// Establish MySQL API connection, if not- fail with err
MYSQL *con = mysql_init(NULL);
if (con == NULL) {
finish_with_error(con);
}
// Connection string.
if (mysql_real_connect(con, "localhost", "user", "password",
NULL, 0, NULL, 0) == NULL){
finish_with_error(con);
}
if (argv[1] == NULL){
printf("No query passed, terminating script \n");
return 1;
}
if (argv[1] != NULL) {
if( strcmp( argv[1], "--help" ) == 0 ) {
printf("This program was created to interact with MySQL, by checking and updating live network stats\n");
printf("It has 2 parameters, an IP address to look in the database for and a value to update a field by, \
if that IP address is found. ");
printf("If the value is not found, the program will insert a new row.");
return 1;
}
// Works out how much memory to allocate to buffer for snprintf
// Originally cmd_len was 65- as this was the amount of bits needed by the address string.
// This was changed to MAXLEN to prevent SEGFAULTS and give the function breathing room.
size_t cmd_len = MAXLEN;
size_t param_len = sizeof(argv[2]);
size_t q_len = cmd_len + param_len;
// Allocates that memory to a buffer, referenced as query
char *query = malloc(sizeof(char) * q_len);
snprintf(query, q_len, "SELECT EXISTS(SELECT * FROM `analytics`.`live` WHERE `foreign_addr` = `%s`)", argv[1]);
printf("%s\n", query);
send_query(con, query);
free(query);
// Used to store the result of the MySQL select commands
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL) {
finish_with_error(con);
}
// num_fields stores the number of fields, i and x are counters, answer is 1 or 0
int num_fields = mysql_num_fields(result);
int i = 0;
// Loops through each row in the answer statement.
// There will only be one row in the answer, which will be 1 or 0
// Basically, if the IP is found.
MYSQL_ROW row;
while ((row = mysql_fetch_row(result))){
for (i=0; i<num_fields; i++) {
// If the IP isn't in the table
if(!atoi(row[i]))
send_query(con, argv[1]);
// If the IP is already in the table
if(atoi(row[i])) {
snprintf(query, q_len, "UPDATE analytics.live SET count=count+1 WHERE foreign_addr = '%s'", argv[1]);
printf("%s\n", query);
free(query);
snprintf(query, q_len, "UPDATE analytics.live SET dat_sent = dat_sent + %s", argv[2]);
printf("%s\n", query);
free(query);
}
}
}
mysql_close(con);
return 1;
}
mysql_close(con);
return 0;
}
I've been like 3 hours on this and I can't make this work.
I read MySQL C API documentation like 10 times about mysql_stmt functions.
What I need is like this: mysql_stmt_fetch()
The thing is I need a parametrized query because there is 1 user input.
Code is as follows:
char* regSol(char* token,MYSQL *conn){
char* regnr;
MYSQL_STMT *stmt;
MYSQL_BIND bind[1];
unsigned long str_length;
/*
* Validation
*/
stmt = mysql_stmt_init(conn);
char *sql="SELECT REGNR,Token FROM registed WHERE Token=?";
if(mysql_stmt_prepare(stmt,sql,strlen(sql))){
fprintf(stderr, " mysql_stmt_prepare(), SELECT failed\n");
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
exit(1);
}
memset(bind, 0, sizeof(bind)); //clears the structure.
bind[0].buffer= 0;
bind[0].buffer_length= 0;
bind[0].length= &str_length;
if(mysql_stmt_bind_result(stmt,bind))
{
fprintf(stderr, " mysql_stmt_bind_result(), failed\n");
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
exit(1);
}
/*
fetch data
*/
unsigned long long nrow=0;
mysql_stmt_fetch(stmt);
if (str_length > 0)
{
char *data= (char*) malloc(str_length);
bind[0].buffer= data;
bind[0].buffer_length= str_length;
mysql_stmt_fetch_column(stmt, bind, 0, 0);
fprintf(stdout,"DEBUG !! - %s - !!\n",data);
}
return NULL;
}
I already tested mysql_stmt_bind_result and other functions.
The first try was preparing, binding and execute. fetch num of rows and it was always 0. No matter what, always 0.
Can anyone tell me the right way to get a result from a parametrized query?
EDIT 1:
new code that seems what will work but something is weird:
char* regSol(char* token,MYSQL *conn){
/*
* Needs to be completed. I have no idea why I can make this work
* Tested a lot of functions and got some SEGVs and 0 rows.
* And results that aren't even in the database
*/
char* regnr;
MYSQL_STMT *stmt;
MYSQL_BIND bind[1];
unsigned long str_length;
/*
* Validation
*/
stmt = mysql_stmt_init(conn);
char *sql="SELECT REGNR FROM registed WHERE Token=?";
if(mysql_stmt_prepare(stmt,sql,strlen(sql))){
fprintf(stderr, " mysql_stmt_prepare(), SELECT failed\n");
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
exit(1);
}
memset(bind, 0, sizeof(bind)); //clears the structure.
bind[0].buffer_type=MYSQL_TYPE_STRING;
bind[0].buffer=(char*)token;
bind[0].buffer_length=strlen(token)+1;
bind[0].length= &str_length;
if(mysql_stmt_bind_param(stmt,bind))
{
fprintf(stderr, " mysql_stmt_bind_param(), failed\n");
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
exit(1);
}
if(mysql_stmt_execute(stmt)){
fprintf(stderr," mysql_stmt_execute(), failed\n");
fprintf(stderr, "%s\n",mysql_stmt_error(stmt));
exit(1);
}
/*
fetch data
*/
//bind result
MYSQL_BIND resbind[1];
unsigned long reslen=0;
resbind[0].buffer=0;
resbind[0].buffer_length=0;
resbind[0].length=&reslen;
if(mysql_stmt_bind_result(stmt,resbind)){
fprintf(stderr," mysql_stmt_bind_result(), failed\n");
fprintf(stderr, "%s\n",mysql_stmt_error(stmt));
exit(1);
}
mysql_stmt_fetch(stmt);
if (reslen > 0) //size of buffer?
{
char *data=(char*)malloc(reslen);
bind[0].buffer=data;
bind[0].buffer_length=reslen;
mysql_stmt_fetch_column(stmt, bind, 0, 0);
fprintf(stdout,"Result Len:%lu\nRegistation NR:%s",reslen,data);
free(data);
}
return "1";
}
The out is:
mysql_stmt_execute(), failed
Got packet bigger than 'max_allowed_packet' bytes
I think it's on here:
if(mysql_stmt_execute(stmt)){
fprintf(stderr," mysql_stmt_execute(), failed\n");
fprintf(stderr, "%s\n",mysql_stmt_error(stmt));
exit(1);
}
So,I created MYSQL_BIND and prepare to bind params (input).
Then I executed. It makes an error which I don't know what It is.
I'm googling how I can access a char* to see the current sql query for troubleshooting.
I think, you have a couple of errors:
1) your query has one (input) parameter and 2 (output) columns, but your defining just one MYSQL_BIND, maybe for input parameter.
2) when you initialize:
bind[0].buffer= 0;
bind[0].buffer_length= 0;
bind[0].length= &str_length;
if this bind is for input parameter, you must change to:
bind[0].buffer= token;
bind[0].buffer_length= strlen(token) + 1;
and pass it with this call:
mysql_stmt_bind_param(stmt,bind);
3) where is your mysql_stmt_execute command? fetch dont work is your query is not executed
I dont check fetch code, but it looks like fine (notice me if not)
I 'm doing an data logger project where i get data from the sensors and store them in a database . I'm using mysql database which is hosted on Beaglebone (Arm linux based computer ),i'm using C api's to work with the mysql database.
I poll the sensors with a sample time of 5 seconds and get data from them and store them onto the tables as per the below code , the code does what is meant to do i just wanted to know whether there's an efficient way of updating the tables .Below is the code
#include <my_global.h>
#include <mysql.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[])
{
/* creates a new mysql object */
MYSQL *con = mysql_init(NULL);
float tempval = 0;
float humidval=0;
char query[100]={0};
if (con == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
/* connect to db */
if(mysql_real_connect(con,"localhost","root","passwrd12#",0,0,0,0)==NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
/* Select the db */
if(mysql_select_db(con,"TestDb")!=0)
{
fprintf(stderr,"%s \n",mysql_error(con));
mysql_close(con);
exit(1);
}
while(1)
{
//Read temperature and humidity sensors on pin1 and pin2
tempval=Read_Sensordata(1);
humidval=Read_Sensordata(2)
memset(query,0,sizeof query);
/* update the temperature and humidity values */
sprintf(query,"UPDATE Datavalues SET Temperature = %f,Humidity = %f,Time=NOW() WHERE Rownum=0",tempval,humidval);
if (mysql_query(con,query))
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
usleep(5000000);
}
mysql_close(con);
exit(0);
}
Rather than execute a fresh query each time, you could prepare the query once and execute it each time with the revised values. For example (without any error checking):
strmov(query, " \
UPDATE Datavalues \
SET Temperature = ?, \
Humidity = ?, \
Time = NOW() \
WHERE Rownum = 0 \
");
MYSQL_STMT *stmt = mysql_stmt_init(con);
mysql_stmt_prepare(stmt, query, strlen(query));
MYSQL_BIND bind[2];
memset(bind, 0, sizeof(bind));
bind[0].buffer_type = bind[1].buffer_type = MYSQL_TYPE_FLOAT;
bind[0].buffer = (char *) &tempval;
bind[1].buffer = (char *) &humidval;
mysql_stmt_bind_param(stmt, bind);
while (1) {
tempval = Read_Sensordata(1);
humidval = Read_Sensordata(2);
mysql_stmt_execute(stmt);
usleep(5000000);
}
mysql_stmt_close(stmt);
Furthermore, you may wish to consider utilising MySQL's Automatic Initialization and Updating for TIMESTAMP and DATETIME to save you having to explicitly set the Time column from within the UPDATE command.
I have read the documentation many times and i have searched on google and i found a lot of example and the code below is the result of my research.
But now i have a big problem and i don't find the solution to fix it.
The code below executes the query but doesn't display the result, it returns always 0 row while it have to return 2 rows... i don't understand where is the mistake.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <mysql/mysql.h>
#define STRING_SIZE 50
#define SELECT_SAMPLE "select p.id_paz from pazienti p where p.id_doc = ?"
int main(void)
{
MYSQL *conn;
MYSQL_STMT *stmt;
MYSQL_BIND pbind[1],result[1]; /* results */
unsigned long length;
int row_count;
char login[STRING_SIZE];
my_bool is_null;
unsigned long plength;
char *pdata;
my_bool p_is_null;
// Open Database
const char *server = "localhost";
char *user = "root";
char *password = "password"; /* set me first */
char *database = "ProgettoSi";
conn = mysql_init(NULL);
/* Connect to database */
if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) {
//...
}
// Allocate statement handler
stmt = mysql_stmt_init(conn);
if (mysql_stmt_prepare(stmt, SELECT_SAMPLE, strlen(SELECT_SAMPLE)))
{
//...
}
fprintf(stdout, " prepare, SELECT successful\n");
plength = STRING_SIZE * sizeof(char);
p_is_null = 0;
pdata = (char*)malloc( STRING_SIZE * sizeof(char) );
/* STRING PARAMETER */
pbind[0].buffer_type= MYSQL_TYPE_STRING;
pbind[0].buffer= (char *)pdata;
pbind[0].buffer_length=STRING_SIZE * sizeof(char);
pbind[0].is_null= &p_is_null;
pbind[0].length= &plength;
if( mysql_stmt_bind_param( stmt, pbind ) ) {
//...
}
mysql_real_escape_string( conn, pdata, "123", strlen("123")*sizeof(char) );
plength = strlen( pdata ) + 1;
printf( "Executing query with parameters %s. \n", pdata);
/* Execute the SELECT query */
if (mysql_stmt_execute(stmt))
{
//...
}
/* Bind the result buffers for all 4 columns before fetching them */
result[0].buffer_type= MYSQL_TYPE_STRING;
result[0].buffer= (char *)login;
result[0].buffer_length= STRING_SIZE;
result[0].is_null= &is_null;
result[0].length= &length;
if (mysql_stmt_bind_result(stmt, result))
{
//...
}
if (mysql_stmt_store_result(stmt))
{
//...
}
row_count= 0;
fprintf(stdout, "Fetching results ...\n");
while (!mysql_stmt_fetch(stmt))
{
row_count++;
fprintf(stdout, " row %d\n", row_count);
/* column 2 */
fprintf(stdout, " column1 (string) : ");
if (is_null)
fprintf(stdout, " NULL\n");
else
fprintf(stdout, " %s(%ld)\n", login, length);
}
/* Validate rows fetched */
fprintf(stdout, " total rows fetched: %d\n", row_count);
/* Close the statement */
if (mysql_stmt_close(stmt))
{
//...
}
return 0;
}
It works if i insert manually the value in the query.
#define SELECT_SAMPLE "select p.id_paz from pazienti p where p.id_doc = 123"
if i execute this query and obviously comment the code in more... it works...
mysql_stmt_fetch has four possible return values: 0 (success), 1 (error), MYSQL_NO_DATA and MYSQL_DATA_TRUNCATED. Your loop terminates on anything other than success - but you don't check what actually happened. You might have 0 rows returned, or you might have some error condition best checked through mysql_stmt_errno() and mysql_stmt_error()...