Using a variable inside a mysql_query construction as value - mysql

I need to refill some lines of a table in mysql, and I'm using the C API. The table has 2 columns titled "VARIABLE" and "VALUE", and 4 lines with the names and values of 4 variables.
I can refill any value, for example the value of VAR1, by the code:
if(mysql_query(conn, "REPLACE INTO TAULA_DADES SET VARIABLE='VAR1',VALOR=3")){
finish_with_error(conn);
}
However, I don't know how to put the value of a C variable in the field, for example:
int a;

Something like this should work (not tested, just an example of possible approach):
MYSQL_STMT *stmt = mysql_stmt_init(conn);
char stmt_text[] = "REPLACE INTO TAULA_DADES SET VARIABLE=?,VALOR=?";
mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
/* Bind the data for the 2 parameters */
MYSQL_BIND bind[2];
memset(bind, 0, sizeof(bind));
/* First parameter */
char var1[16] = "VAR1";
unsigned long var1_len = strlen(var1);
bind[0].buffer_type = MYSQL_TYPE_STRING;
bind[0].buffer = var1;
bind[0].buffer_length = 16;
bind[0].is_null = 0;
bind[0].length = &var1_len;
/* Second parameter */
int a = 123;
bind[1].buffer_type = MYSQL_TYPE_LONG;
bind[1].buffer = (char *)&a;
bind[1].is_null = 0;
bind[1].length = 0;
mysql_stmt_bind_param(stmt, bind);
mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
In the real program you should check the return value of each statement adding the code for error management.
You can also pass variables via sprintf (e.g. take a look at How to pass variable in mysql_query) but it presents a higher security risk (at least consider the mysql_real_escape_string() function for user-supplied values).
Further details:
mysql_stmt_execute()
C API Prepared Statement Data Structures

Related

Calling MySQL stored procedure in c, passing variable argument

I made a database in MySQL and I created some Stored Procedures. Now I need to launch these SP using a C program.
I've already connected my db to c successfully, using:
char u[255];
char p[255];
int main (int argc, char *argv[])
{
scanf("%s",u);
scanf("%s",p);
conn = mysql_init (NULL);
login = mysql_real_connect(conn, "localhost",u,p, "ASL", 3306, NULL, 0);
}
I'm able to calling a SP without any parameter. For example my SP mostra_pazienti()shows all the rows contained in the MySQL table 'paziente', and I made in this way:
query = "call mostra_pazienti()";
mysql_query (conn,query);
MYSQL_RES *result = mysql_store_result(conn);
int num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
printf(" %s ", row[i] ? row[i] : "NULL");
}
printf ("\n");
}
}
But basically now I need to run a procedure which takes some parameters as input.
For example MySQL procedure esame_aggiungi(IN code CHAR(5),IN name VARCHAR(30),IN cost FLOAT) insert a new row in the table exam.
So, in C, how can I take the parameters code, name, and cost using scanf(), and how can I use them to execute my Stored procedure?
If you're asking "how do I build the CALL MYPROC(ARG1, ARG2...) string within my C program", you can use the function snprintf for that, which writes formatted data to a string of known length.
char query[1000];
snprintf(query, 1000, "CALL MYPROCEDURE(\"%s\", \"%s\", %f);", code, name, cost);
mysql_query(conn, query);
Note that bounds checking for the constraints in the MySQL table (i.e. the field code is of type CHAR (5) and name is of type VARCHAR (30)) must be taken care of as well. A column with type CHAR(N) rather than VARCHAR will contain exactly N characters.

MySQL Connector C/C API - Query with special characters

I a C program I have a function that takes in parameter a domain name:
void db_domains_query(char *name);
With mysql_query() I test if the domain name is existing in a database. If it's not the case, I insert the new domain name:
...
char *query[400];
sprintf(query, "SELECT Id, DomainName FROM domains WHERE domainName LIKE '%s'", name);
if (mysql_query(con, query))
finish_with_error(con);
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
finish_with_error(con);
MYSQL_ROW row;
if ((row = mysql_fetch_row(result)))
printf("Element exists : %s %s\n", row[0], row[1]);
else
printf("Element %s doesn't found\n", name);
// Then insert the new domain name ...
This portion of code works perfectly if name contains only "normal characters". However, for domain names that contain "special characters" the query seems incorrect even if those are in the database for instance :
name = undaben.de : Element exists : 100 undaben.de
name = ®here.com : Element ®here.com is not found.
name = §travel.us : Element §travel.us is not found.
Extract of the table :
+-----+--------------+
| id | domainname |
+-----+--------------+
| 100 | undaben.de |
| 162 | §travel.us |
| 197 | ®here.com |
+-----+--------------+
The collation of the field domainname is utf8_unicode_ci.
So how can I pass to mysql_query all domain names including the "special" ones ?
I recommend you to avoid the C API unless you have a compelling reason to use it. The C++ API es way more usable.
You are embedding your arguments within your query string. This has a number of problems, including security risks. If you insist in this approach, in order to prevent problems with parameters messing with your query, you need to ensure a few things:
Make sure that your data encoding matches the encoding of the MySQL Client connection (this may be different from your database encoding). If your connection is set up as UTF-8, then you need to make sure that special characters such as © are encoded also in UTF-8 when used as input to the sprintf function.
You also need to protect from other SQL escape characters (like '). For this you can use the mysql_real_escape_string function, as mentioned in Efficiently escaping quotes in C before passing to mysql_query.
However, you should very likely be using prepared statements which circumvent these issues. You still need to make sure that your input data encoding matches the encoding of your client connection, but everything else shall be easier to handle.
I paste an example of a parameterized query using the C API with prepared statements looks like (example from http://lgallardo.com/2011/06/23/sentencias-preparadas-de-mysql-en-c-ejemplo-completo/). Note the example is for integers, not strings, you need to adapt to your use case.
sql = "select count(*) from addresses where id = ?";
// Open Database
openDB(&conn);
// Allocate statement handler
stmt = mysql_stmt_init(conn);
if (stmt == NULL) {
print_error(conn, "Could not initialize statement handler");
return;
}
// Prepare the statement
if (mysql_stmt_prepare(stmt, sql, strlen(sql)) != 0) {
print_stmt_error(stmt, "Could not prepare statement");
return;
}
// Initialize the result column structures
memset (param, 0, sizeof (param)); /* zero the structures */
memset (result, 0, sizeof (result)); /* zero the structures */
// Init param structure
// Select
param[0].buffer_type = MYSQL_TYPE_LONG;
param[0].buffer = (void *) &myId;
param[0].is_unsigned = 0;
param[0].is_null = 0;
param[0].length = 0;
// Result
result[0].buffer_type = MYSQL_TYPE_LONG;
result[0].buffer = (void *) &myNumAddresses;
result[0].is_unsigned = 0;
result[0].is_null = &is_null[0];
result[0].length = 0;
// Bind param structure to statement
if (mysql_stmt_bind_param(stmt, param) != 0) {
print_stmt_error(stmt, "Could not bind parameters");
return;
}
// Bind result
if (mysql_stmt_bind_result(stmt, result) != 0) {
print_stmt_error(stmt, "Could not bind results");
return;
}
// Set bind parameters
myId = id;
// Execute!!
if (mysql_stmt_execute(stmt) != 0) {
print_stmt_error(stmt, "Could not execute statement");
return;
}
if (mysql_stmt_store_result(stmt) != 0) {
print_stmt_error(stmt, "Could not buffer result set");
return;
}
// Init data
(*numAddresses) = 0;
// Fetch
if(mysql_stmt_fetch (stmt) == 0){
(*numAddresses) = myNumAddresses;
}
// Deallocate result set
mysql_stmt_free_result(stmt); /* deallocate result set */
// Close the statement
mysql_stmt_close(stmt);
// Close Database
closeDB(conn);
Again, if you can use some other client library (like the C++ client) your code will be way shorter and readable.
My bad, as #jjmontes mentioned it seems that the sent string was encoded in 'latin1'.
Using the function mysql_set_character_set(conn, "utf8") before doing the query solved this problem.
Now, I will try to use prepared statements instead of query strings.
thanks again!

Reassigning Variables when Passing Structures to Functions in Matlab

I'm working with a series of MatLab functions that take 10+ single-value arguments. I've used structures to pass the arguments to keep the code readable. An example of a function header (input is a structure):
function output = myFunction(input)
I'm finding that typing the structure name throughout the code makes it more difficult to read:
calc1 = input.var1 * input.var2;
calc2 = input.var2 * input.var3;
I realize the example above could conveniently use an array, but most of my arguments are unrelated and of varying types. Additionally, the operations I'm carrying out on the variables are more complicated than the example above and don't lend themselves to an array.
I could create variable names to accept the values from the input structure:
function output = myFunction(input)
var1 = input.var1;
var2 = input.var2;
var3 = input.var3;
calc1 = var1 * var2;
calc2 = var2 * var3;
Doing this creates a long block at the top of the function which does nothing but reassign the input variables, and the data has to be copied so there is a performance penalty. On the other hand, the code is easier to read.
Is there any coding convention that could provide guidance? I've found plenty of resources here and on Google that suggest passing large amounts of data to MatLab functions using structures, but precious little on how to do so intelligently.
How about if you write a function that parses the input arguments, and design it so that it accepts either a structure as input, or a list of variables.
Example:
function output = myFunc(varargin)
narginchk(1,3);
[var1,var2,var3] = parseInput(varargin{:});
fprintf('var 1 = %g\n', var1);
fprintf('var 2 = %g\n', var2);
fprintf('var 3 = %g\n', var3);
output = var1+var2+var3;
end
function [var1,var2,var3] = parseInput(varargin)
if nargin == 1 && isstruct(varargin{1})
var1 = varargin{1}.var1;
var2 = varargin{1}.var2;
var3 = varargin{1}.var3;
elseif nargin == 3
[var1,var2,var3] = deal(varargin{:});
else
error('myFunc:parseInput', 'Incorrect input')
end
end
Now we can call the function as:
x = myFunc(1,2,3)
or:
in = struct('var1',1, 'var2',2, 'var3',3);
x = myFunc(in)
Of course you could add more strict validation to check the input (see validateattributes and InputParser)

recently switch from sqlite to mysql. need to convert some code in c

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

How to pass variable in mysql_query

I try to execute mysql query passing variable. Here is my code
char str[100] = "My String";
mysql_query(conn, printf("INSERT INTO table VALUES %s"), str);
I get that warning during compile process
warning: passing argument 2 of ‘mysql_query’ makes pointer from integer without a cast
What I miss ?
Extending #ckruse's answer, you should take care to use mysql_real_escape_string() if your string comes from arbitrary sources.
int insert_data(MYSQL * mysql, char * str, int len)
{
if (len < 0) {
len = strlen(str);
}
char esc[2*len+1];
unsigned long esclen = mysql_real_escape_string(mysql, esc, str, len);
char statement[512];
snprintf(statement, sizeof statement, "INSERT INTO table VALUES ('%s')", esc);
return mysql_query(mysql, statement);
}
(An alternative could be mysql_hex_string() if dealt with correctly.)
You cannot do that. printf() returns the number of characters printed. You have to create the string before calling mysql_query():
char statement[512], *my_str = "MyString";
snprintf(statement, 512, "INSERT INTO table VALUES ('%s')", str);
mysql_query(conn, statement);
Also, be careful when creating those query strings. Don't use functions like sprintf() if you cannot be sure how long the resulting string is. Don't write over the boundaries of the memory segment.
you should put "'' in front and after the string
like this
mysql_query(conn, printf("INSERT INTO table VALUES ('%s')"), str);