Printing records alternative way - mysql

Is there a way to directly display the content of a query in Mysql using C?
What I mean is:
through mysql shell if I type : SELECT * FROM table_name; I get the query result in a neat and formatted way.
If I want to do the same thing using Api C I have to write several lines of codes and the final result is far from being nice (at least this is my personal experience )
For example :
void display_Table1(MYSQL *conn)
{
int jj,ii;
char query[512];
sprintf(query, "SELECT * FROM Table1 ;");
if (mysql_query (conn, query)) {
printf("\nErrore query:\n");
printf("%s", mysql_error(conn),"\n");
result = mysql_store_result(conn);
if (result) {
num_rows = mysql_num_rows(result);
num_fields =mysql_num_fields(result);
//printf("Number of rows=%u Number of fields=%d \n", num_rows,num_fields);
//printf(" ");
}
else
{
printf("Result set is empty");
}
// Print column headers
fields = mysql_fetch_fields(result);
for(jj=0; jj < num_fields; jj++)
{
printf("\n%s\t\t",fields[jj].name);
}
printf("\n\t ");
// print query results
while(row = mysql_fetch_row(result)) // row pointer in the result set
{
for(ii=0; ii < num_fields; ii++)
{
printf("%s\t", row[ii] ? row[ii] : "NULL"); // Not NULL then print
}
printf("\n");
}
if(result)
{
mysql_free_result(result);
result = NULL;
}
}
}
That's a knotty problem to solve. I get headers one after the other in a vertical way.
I also get
Commands out of sync; you can't run this command now

Firstly, there is no direct way to print out a formatted display. What you can do, is use
MYSQL_FIELD *field = mysql_fetch_field (resultset);
col_len = field->max_length;
if(col_len < strlen(field->name))
col_len = strlen(field->name);
to find out the maximum width of a column, and the space the data accordingly.

Related

C - alternative using snprintf to prepare MySQL statements?

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;
}

MySQL command to delete a row in C is not working

I don't usually code using C programming language but I learned it in school (so please bear with me because I am still a newbie).
In short, I was recently assigned to write code in C in order to delete rows from a table in MySQL database.
I used stackoverflow and other resources to help me with this code!
This is my code (not all of it):
void delete_rows(MYSQL *con)
{
char selection_query[256];
char deletion_query[256];
sprintf(selection_query, "SELECT id FROM <table> WHERE status = 'PROCESSING'\
AND started < DATE(NOW()) - INTERVAL %d DAY", expire_processing_days);
if (mysql_query(con, selection_query))
{
finish_with_error(con);
}
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
{
finish_with_error(con);
}
int num_fields = mysql_num_fields(result);
MYSQL_ROW row;
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
printf("Deleting process with id: %s ", row[i] ? row[i] : "NULL");
sprintf(deletion_query, "DELETE FROM <table> WHERE id = %d", row[i]);
if (mysql_query(con, deletion_query))
{
finish_with_error(con);
}
mysql_commit(con);
}
printf("\n");
}
mysql_free_result(result);
}
int main()
{
MYSQL *con;
DB_CONN_PARAMS *params = calloc(1,sizeof(DB_CONN_PARAMS));
//just an alternative way of passing connection params, find a struct easier
strcpy(params->host, <host>);
strcpy(params->user, <user>);
strcpy(params->pass, <password>);
strcpy(params->db, <database>);
MYSQL * connect_db(DB_CONN_PARAMS *params);
con = connect_db(params);
//we don't need the struct anymore
free(params);
params = NULL;
//kill processes that are incomplete/hanging
delete_rows(con);
//close mysql connection
mysql_close(con);
return EXIT_SUCCESS;
}
So, the code above compiles and runs without any errors, it prints out the ids of the rows that I want to delete. But when I go to the database to check the rows, they are still there!
Is there anything I am missing?
Ok, I have figured it out finally!
I changed the %d to %s in the following line:
sprintf(deletion_query, "DELETE FROM WHERE id = %d", row[i]);.
Because row[i] is a string, I was blind to that.
I was able to figure it out by printing the whole MySQL command and noticed that the id passed is wrong!
Thank you everyone for your attempts to help me.

change string file?

I have an output of a string that is:
I need to print out only the parts that are between"tele": and then the ",". for example the first one i need to print out is hel. In the above string output. "text":"hel","source": is the first part. Every where there is a "tele": and the "," i need to be printed.
the code i have written so far prints out only the first one and is shown below
int comm_poss;
string econ;
tax= mes.find("tele");
econ=mes.substr(tax,15);
cout<<"msg test : "<<econ;
This prints out tele":"hel"," but not the other part that is between the "tele" and ","
how do i print only whats between those two and make the code do it multiple times?
thanks
EDIT: the other part in the output is "tele":"FIRS","code":" found near the end
Save yourself some trouble and use a JSON parser. For example using JsonCpp library and reading the JSON file from stdin (untested):
Json::Value root;
std::cin >> root;
for (int i = 0; i < root.size(); i++) {
std::string text = root[i]["text"].asString();
std::cout << text << std::endl;
}
Could something like this help.
string txt_test;
size_t poss_text;
poss_text= replyMsg.find("text:\":\""); // Search for text":"
replyMsg=replyMsg.substr(poss_text + 8); // Get rest of string
// Add 8 to get beyond text":"
poss_text= replyMsg.find("\","); // Search for ",
txt_test = replyMsg.substr(0, poss_text); // Get from start to ",
cout<< "msg test : " << txt_test;
You should however always check whether your string were found:
if (poss_text != std::string::npos)
{
// Found - so go on
}
else
{
// Not found - stop now
}
Now you can add the loop:
int main()
{
string replyMsg = "HEJtext:\":\"first\",\"hhhtext:\":\"second\",";
string txt_test;
size_t poss_text = 1;
while(poss_text != std::string::npos) // Loop while there is still something in replyMsg
{
poss_text= replyMsg.find("text:\":\""); // Search for text":"
if (poss_text != std::string::npos)
{
replyMsg=replyMsg.substr(poss_text + 8); // Get rest of string
// Add 8 to get beyond text":"
poss_text= replyMsg.find("\","); // Search for ",
if (poss_text != std::string::npos)
{
txt_test = replyMsg.substr(0, poss_text); // Get from start to ",
cout<< "msg test : " << txt_test << std::endl ;
replyMsg=replyMsg.substr(poss_text); // Prepare for next search
}
}
}
return 0;
}
This is a working solution.
I will not use any library since you probably want to know how to do it from scratch.
1. Using Strtok() with delim(':') and checking if the 6 characters to
the left is equal to "text", If TRUE, then pickup all characters to the right
until you hit ",".
2. When you're picking up characters to the right, to avoid reading past your domain, modify the content string by adding a '$' symbol to the end.
#include <iostream>
void get_text(char * token);
int main(){
char =content[]="586162004425048066\",\"text\":\"hel\",\"source\":...\"text\":\"yo\";$";
char * token;
token=strtok(content,":");
get_text(token);
while(token=strtok(NULL,":")){
get_text(token);
}
}
void get_text(char * token){
unsigned int len=strlen(token);
std::string temp;
if (len>=6){ // Reading the 6 characters to the left and storing it in temp
for (int i=-6; i<0; i++){
temp=temp+token[len+i];
}
}
if (temp=="\"text\""){
temp="";
unsigned i=len;
while(token[i]!=',' and token[i]!='$'){ // retrieve characters to the right until you hit a ',' or '$' (which indicates end of line as a boundary condition)
temp=temp+token[i];
i++;
}
std::cout<<temp;
}
}
OUTPUT
"hey" "yo"

Converting a MySQL result into a JSON string in C

How do I convert a result from a MySQL query to a JSON string in C?
Of course I know how to do it, I just wondered if there's already a solution to copy-paste, realizing I don't want to write boiler-plate code.
And how do I Google for this question? Google just disregard the c and shows results for PHP etc.
The C file I made to do this is four times faster than the corresponding PHP file, using ab to measure performance:
ab -k -c 300 -n 10000 localhost/tiny.php
Time per request: 393.072 [ms] (mean)
With C:
ab -k -c 300 -n 10000 localhost/cgi/tiny.fcgi
Time per request: 98.237 [ms] (mean)
This is assuming Apache spawns 10 processes of tiny.fcgi, and PHP does not use FastCGI.
FastCgiServer /var/www/cgi/tiny.fcgi -processes 10
This is the PHP code, which connects to MySQL, fetch a query result and echo the JSON representation:
<?php
$mysqli = mysqli_connect("localhost", "user", "password", "db");
mysqli_set_charset($mysqli, "utf8");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$result = mysqli_query($mysqli, "SELECT * FROM table");
$rows = array();
while ($row = mysqli_fetch_assoc($result)) {
$rows[] = $row;
}
echo json_encode($rows);
Let's step through the C code. I will use the PHP internal struct smart_str to handle strings (this is what PHP use in the json_encode function). Using the naive char* for strings will be catastrophical, because the number of malloc and free will be huge due to string append usage.
We want to use FastCGI:
#include "fcgi_stdio.h"
int main(void)
{
while(FCGI_Accept() >= 0)
{
}
FCGI_Finish();
return 0;
}
Analysing this with valgrind gives 768 bytes still reachable at end, which we will ignore (bug in FastCGI probably).
Next comes MySQL connection and query:
MYSQL* connection = NULL;
MYSQL_RES* result = NULL;
connection = mysql_init(NULL);
if (connection == NULL)
{
(void) FCGI_fprintf(FCGI_stderr, "Could not connect to MySQL: %s\n", mysql_error(connection));
continue;
}
// Connect to database
if (mysql_real_connect(connection, "localhost", "user", "password", "db", 0, NULL, 0) == NULL)
{
close_mysql_with_error(connection);
continue;
}
// Select from pages
if (mysql_query(connection, "SELECT * FROM table") != 0)
{
close_mysql_with_error(connection);
continue;
}
// Get result
result = mysql_store_result(connection);
// Abort if no result
if (result == NULL)
{
close_mysql_with_error(connection);
continue;
}
(I use continue instead of exit or return, because this code is within the while loop seen above.)
Nothing strange here, right?
The next part will create our smart_str JSON variable, pass it to function result_to_json and then echo the result.
smart_str json = {0, 0, 0};
result_to_json(result, &json);
if (json.c != NULL)
(void) FCGI_printf("json = %s\n", json.c);
smart_str_free(&json);
The result_to_json is just a loop over the rows in the MySQL result:
static void result_to_json(MYSQL_RES *result, smart_str* json)
{
MYSQL_ROW row;
int i;
int num_fields = (int) mysql_num_fields(result);
smart_str** fields = get_field_names(result, num_fields);
if (fields == NULL)
{
return;
}
smart_str_appendc(json, '[');
while ((row = mysql_fetch_row(result, num_fields)))
{
smart_str_appendl(json, "{", 1);
for (i = 0; i < num_fields; i++)
{
// key
smart_str_appendl(json, "\"", 1);
smart_str_appendl(json, fields[i]->c, fields[i]->len);
smart_str_appendl(json, "\": ", 3);
if (row[i] == NULL)
{
smart_str_appendl(json, "null", 4);
smart_str_appendl(json, ", ", 2);
}
else
{
smart_str_appendl(json, "\"", 1);
smart_str_appendl(json, row[i], strlen(row[i]));
smart_str_appendl(json, "\", ", 3);
}
}
if (json == NULL) {
free_field_names(fields, num_fields);
return;
}
// Strip last ','
json->len--;
json->len--;
smart_str_appendl(json, "}, ", 3);
}
if (json == NULL)
{
free_field_names(fields, num_fields);
return;
}
// Strip last ','
json->len--;
json->len--;
smart_str_appendl(json, "]", 1);
smart_str_0(json);
free_field_names(fields, num_fields);
return;
}
Finally, get_field_names and free_field_names:
static smart_str** get_field_names(MYSQL_RES *my_result, int num_fields)
{
smart_str** fields; // Array of pointers
MYSQL_FIELD *field = NULL;
int i;
// Allocate size of array
fields = malloc(num_fields * sizeof(smart_str*));
if (fields == NULL)
{
return NULL;
}
for (i = 0; i < num_fields; i++)
{
field = mysql_fetch_field(my_result);
if (field == NULL) {
// TODO: Free fields[]
free(fields);
return NULL;
}
fields[i] = malloc(sizeof(smart_str));
if (fields[i] == NULL) {
// TODO: Free fields[]
free(fields);
return NULL;
}
else
{
fields[i]->c = NULL;
smart_str_appendl(fields[i], field->name, strlen(field->name));
}
return fields;
}
static void free_field_names(smart_str** strings, int size)
{
int i;
for (i = 0; i < size; i++)
{
smart_str_free(strings[i]);
free(strings[i]);
}
free(strings);
}
There you go! What's left to do is to measure against FastCGI enabled PHP, to see how much the PHP performance improves.

Objective-C and MySQL

I've been able to connect to a MySQL database in my app and use the C API which is almost exactly like PHP commands (mysql_real_connect(), mysql_query(), mysql_fetch_array(), etc.) and which I am pretty comfortable with I'm just not sure how the data query is returned. Do I use an array or dictionary and then how would I parse it. For example, in PHP I would do something like so (after the connection):
$results = mysql_query("SELECT * FROM theDatabase");
if (mysql_num_rows($results) > 0) {
while($row = mysql_fetch_array($results)) {
print $row;
}
}
What would the objective-c equivalent be? Thanks.
Edit:
OK, so I made some progress - I can make the query and get the number of fields/rows returned, just can't seem to access the data itself. Here's my code, which I stitched together from the MySQL docs and a few other sites:
- (IBAction)dbConnect:(id)sender {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MYSQL mysql;
mysql_init(&mysql);
if (!mysql_real_connect(&mysql, "10.1.1.99", "******", "******", "oldphotoarchive", 0, NULL, 0)) {
NSLog(#"%#", [NSString stringWithUTF8String:mysql_error(&mysql)]);
} else {
MYSQL_RES *result;
MYSQL_ROW row;
unsigned int num_fields;
unsigned int num_rows;
unsigned long *lengths;
if (mysql_query(&mysql,"SELECT * FROM photorecord")) {
// error
} else { // query succeeded, process any data returned by it
result = mysql_store_result(&mysql);
if (result) {
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result))) {
lengths = mysql_fetch_lengths(result);
for(int i = 0; i < num_fields; i++) {
//the line below is my problem, printing row[i] fails, I get the GNU gdb error...
row[i] ? NSLog(#"%#", row[i]) : NSLog(#"wtf");
}
}
} else {// mysql_store_result() returned nothing; should it have?
if (mysql_errno(&mysql)) {
NSLog(# "Error: %s\n", mysql_error(&mysql));
} else if (mysql_field_count(&mysql) == 0) {
// query does not return data
// (it was not a SELECT)
num_rows = mysql_affected_rows(&mysql);
}
}
}
}
[pool release];
}
There's no Apple-supplied Objective-C API for MySQL. There are a few third-party wrappers of the C API, though. Take a look at the MySQL-Cocoa Framework, for example.
Given your familiarity with the PHP and C API, it may be more straightforward for you simply to use the C API. You'll need to handle conversion between objects and C data types, but this isn't much work.
Edit
You're crashing because the row value returned by the mysql API isn't an object, and your format string is telling NSLog to treat it as one. The %# is a format-string placeholder for an object, not a C data type.
It's not clear what the value is in this case. The context seems to imply that it's image data. If that's the case, you'll likely want to create an NSData object from the blob returned by the query, e.g.:
NSData *imageData;
imageData = [[ NSData alloc ] initWithBytes: row[ i ] length: lengths[ i ]];
NSLog( #"imageData: %#", imageData );
/* ...create NSImage, CGImage, etc... */
[ imageData release ];
If your result fields are just strings, use NSString's -initWithBytes:length:encoding: method:
NSString *s;
s = [[ NSString alloc ] initWithBytes: row[ i ] length: lengths[ i ]
encoding: NSUTF8StringEncoding ];
NSLog( #"result column %d: %#", i, s );
[ s release ];