C++/CLI & mySQL: How to form queries from user input/choice - mysql

This is for homework, so I understand if you don't want to just give me the answer. That being said, if you do decide to "give" me anything, please explain what it does, and why, and how, because, to be perfectly honest, I'm in an online program and the teacher/class style is very unhelpful. I.E. When we ask for help, we just get a link to the MSDN main page and are told to figure it out. (PS: if anyone ever considers going to 'City University' for a MS in CS: don't).
I've been working on this 1 problem for over 30 hours now, and searched high and low on this website and many others, and have been coming up with not much to show for it. Any help, explanations, tips, etc, would be greatly appreciated.
The assignment is to take user input in a C++/CLI console app, connect it to a mySQL database via ODBC32, and run a loop asking for user choice about which table to pull up and display. I have done the loop, I have gotten the db connected (I think/hope), but I can't seem to convert the users choice into a valid SQL query, or maybe it's just a display issue. Since I am quite literally teaching myself, I have to admit that I don't really know if this is where the true root of the problem lies, or if I have grossly misunderstood what this code is and does.
My current code:
#include "stdafx.h"
#include <string>
#include <sql.h>
#include <sqlext.h>
#pragma comment( lib, "odbc32.lib" )
#define EMPLOYEE_ID_LEN 32
SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;
SQLRETURN retcode;
SQLHSTMT hstmt = NULL;
SQLSMALLINT sCustID;
SQLCHAR szEmployeeID[EMPLOYEE_ID_LEN];
SQL_DATE_STRUCT dsOrderDate;
SQLINTEGER cbCustID = 0, cbOrderDate = 0, cbEmployeeID = SQL_NTS;
int main()
{
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
retcode = SQLConnect(hdbc, (SQLWCHAR*) "MySqlWorld", SQL_NTS, (SQLWCHAR*)NULL, 0, NULL, 0);
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
bool boolExit = false;
while (boolExit == false)
{
String^ strChoice = "";
do {
if (strChoice == "a")
{
strChoice = "city";
break;
}
else if (strChoice == "b")
{
strChoice = "country";
break;
}
else if (strChoice == "c")
{
strChoice = "countrylanguage";
break;
}
else if (strChoice == "e")
{
boolExit = true;
break;
}
else
{
Console::WriteLine();
Console::WriteLine("Please choose from the following options:");
Console::WriteLine("A: Enter last name to retreive first name, home address, and work phone number.");
Console::WriteLine("B: Enter last name to retrieve department.");
Console::WriteLine("C: Enter department to retrieve list of employee last names, addresses, and work phone numbers for members of that department.");
Console::WriteLine("E: Exit");
strChoice = Console::ReadLine()->ToLower();
}
} while (true);
if (boolExit == false)
{
char* cstrTempQuery = (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(strChoice);
SQLCHAR sqlTempQuery[32];
strcpy_s((char*)sqlTempQuery, _countof(sqlTempQuery), (const char *)cstrTempQuery);
retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, EMPLOYEE_ID_LEN, 0, sqlTempQuery, 0, &cbEmployeeID);
retcode = SQLPrepare(hstmt, (SQLWCHAR*)"SELECT * from ?", SQL_NTS);
retcode = SQLExecute(hstmt);
}
} // end while (boolExit == false)
} // end main()
The code results in no errors of any sort, but doesn't do anything. My loop shows, I make a selection, and nothing happens, except that the loop repeats.
I got most of this code from this page: https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function

You cannot bind tablename or field name parameters. You can dynamically construct the query using using curly braces. It is not advised but possible with this:
https://stackoverflow.com/a/11327831/5389997
Something similar to : SELECT * FROM {$mytable}
Since you're specifying your tables that you need then you don't have to worry so much about the SQL injection angle.
It also looks like you're not updating the boilerplate code to have your variables.
#include "stdafx.h"
#include <string>
#include <sql.h>
#include <sqlext.h>
#pragma comment( lib, "odbc32.lib" )
#define QUERY_LEN 32
SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;
SQLRETURN retcode;
SQLHSTMT hstmt = NULL;
SQLCHAR szQueryVar[QUERY_LEN];
SQLCHAR queryVar = SQL_NTS;
int main()
{
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
retcode = SQLConnect(hdbc, (SQLWCHAR*) "MySqlWorld", SQL_NTS, (SQLWCHAR*)NULL, 0, NULL, 0);
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
bool boolExit = false;
while (boolExit == false)
{
String^ strChoice = "";
String^ tableName = "";
String^ queryField = "";
String^ queryVar = "";
do {
if (strChoice == "a")
{
tableName = "address";
queryField = "last_name";
queryVar = Console::ReadLine();
break;
}
else if (strChoice == "b")
{
tableName = "department";
queryField = "last_name";
queryVar = Console::ReadLine();
break;
}
else if (strChoice == "c")
{
tableName = "department";
queryField = "department";
queryVar = Console::ReadLine();
break;
}
else if (strChoice == "e")
{
boolExit = true;
break;
}
else
{
Console::WriteLine();
Console::WriteLine("Please choose from the following options:");
Console::WriteLine("A: Enter last name to retreive first name, home address, and work phone number.");
Console::WriteLine("B: Enter last name to retrieve department.");
Console::WriteLine("C: Enter department to retrieve list of employee last names, addresses, and work phone numbers for members of that department.");
Console::WriteLine("E: Exit");
strChoice = Console::ReadLine()->ToLower();
}
} while (true);
if (boolExit == false)
{
char* cstrTempQuery = (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(strChoice);
SQLCHAR sqlTempQuery[32];
strcpy_s((char*)sqlTempQuery, _countof(sqlTempQuery), (const char *)cstrTempQuery);
retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, QUERY_LEN, 0, sqlTempQuery, 0, &queryVar);
query = (SQLCHAR*)"SELECT * from {$tableName} where {$queryField} = ?";
retcode = SQLPrepare(hstmt, queryVar, SQL_NTS);
retcode = SQLExecute(hstmt);
}
} // end while (boolExit == false)
} // end main()

Related

API call with invalid database connection pointer & misuse error when updating values in table - objective c application

I am working on a messaging iOS application and below is the code to update a table when a new message is received for a chat:
- (BOOL) updateInfoForChat:(Chat*)chat {
BOOL success;
int code = 0;
if (!dbOpen && dbConnection != NULL) {
if (sqlite3_open_v2([[DatabaseManager databasePath] UTF8String], &dbConnection, SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, NULL) == SQLITE_OK) {
dbOpen = YES;
const char* key = [[self getDBKey] UTF8String];
sqlite3_key(dbConnection, key, (int)strlen(key));
chat.lastMessage = [chat.lastMessage stringByReplacingOccurrencesOfString:#"\"" withString:#"%27"];
char *errMsg;
NSString *insertSQL = [NSString stringWithFormat:#"UPDATE Chats SET "
"lastMessageTime = %f, lastMessageText = \"%#\", canReply = \"%#\", isArchived = \"%#\" WHERE chatRoomId = \"%#\" AND lastMessageTime <= (SELECT messageTime FROM Messages WHERE chatRoomId = \"%#\" ORDER BY messageTime DESC LIMIT 1)",
chat.lastMsgTime, chat.lastMessage , chat.canReply ? #"True" : #"False" , chat.isArchived ? #"True" : #"False", chat.chatRoomID, chat.chatRoomID];
const char *sql_stmt = [insertSQL UTF8String];
code = (sqlite3_exec(dbConnection, sql_stmt, NULL, NULL, &errMsg));
if (code == SQLITE_OK) {
//commenting this out as this makes the logs very noisy
}
else {
NSLog(#"This method did not get executed with error: %s",sqlite3_errmsg(dbConnection));
}
sqlite3_close_v2(dbConnection);
dbOpen = NO;
}
else {
NSLog(#"This method did not get executed with error: %s",sqlite3_errmsg(dbConnection));
}
}
return success = (code == SQLITE_OK);
}
Having received messages in a couple of chats, I get the errors below when application hits this code:
API call with invalid database connection pointer
misuse at line 133563 of [d24547a13b]
This method did not get executed with error: bad parameter or other API misuse
Can someone suggest where the issue could be coming from?

How to get all html file with a HTTP GET request using c++?

I need to create a c++ console application that query a site in turn to get the html page.
The site is static because when I queried it in the url I see the html file, so I use this code:
send(Socket, "GET /it/ricette/q-torte_forno_statico.html HTTP/1.1\r\nHost: worldrecipes.expo2015.org/\r\nConnection: close\r\n\r\n", strlen("GET /it/ricette/q-torte_forno_statico.html HTTP/1.1\r\nHost: worldrecipes.expo2015.org\r\nConnection: close\r\n\r\n"), 0);
char buffer[1000000];
int nDataLength;
while ((nDataLength = recv(Socket, buffer, 1000000, 0)) > 0) {
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
cout << buffer[i];
i += 1;
}
}
It doesn't give me any errors but don't show me the whole html page and every time that I call send the request I get different answers ... why?
This code below seems to only work on the index page worldrecipes.expo2015.org and not the sub pages. You might want to look at more advanced webbrowser controls for visual studio for parsing and processing HTML.
Like here : http://www.codeproject.com/Articles/3365/Embed-an-HTML-control-in-your-own-window-using-pla
here : https://msdn.microsoft.com/en-us/library/aa752046(v=vs.85).aspx
and here : http://www.codeproject.com/Articles/3919/Using-the-WebBrowser-control-simplified
Example code:
#include <windows.h>
#include <string>
#include <stdio.h>
using std::string;
#pragma comment(lib,"ws2_32.lib")
HINSTANCE hInst;
WSADATA wsaData;
void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename);
SOCKET connectToServer(char *szServerName, WORD portNum);
int getHeaderLength(char *content);
char *readUrl2(char *szUrl, long &bytesReturnedOut, char **headerOut);
int main()
{
const int bufLen = 1024;
char *szUrl = "http://worldrecipes.expo2015.org/it/ricette/q-torte_forno_statico.html";
long fileSize;
char *memBuffer, *headerBuffer;
FILE *fp;
memBuffer = headerBuffer = NULL;
if ( WSAStartup(0x101, &wsaData) != 0)
return -1;
memBuffer = readUrl2(szUrl, fileSize, &headerBuffer);
printf("returned from readUrl\n");
printf("data returned:\n%s", memBuffer);
if (fileSize != 0)
{
printf("Got some data\n");
fp = fopen("downloaded.file", "wb");
fwrite(memBuffer, 1, fileSize, fp);
fclose(fp);
// SetDlgItemText(hwndDlg, IDC_EDIT4, headerBuffer);
// SetDlgItemText(hwndDlg, IDC_EDIT5, memBuffer);
delete(memBuffer);
delete(headerBuffer);
}
WSACleanup();
return 0;
}
void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename)
{
string::size_type n;
string url = mUrl;
if (url.substr(0,7) == "http://")
url.erase(0,7);
if (url.substr(0,8) == "https://")
url.erase(0,8);
n = url.find('/');
if (n != string::npos)
{
serverName = url.substr(0,n);
filepath = url.substr(n);
n = filepath.rfind('/');
filename = filepath.substr(n+1);
}
else
{
serverName = url;
filepath = "/";
filename = "";
}
}
SOCKET connectToServer(char *szServerName, WORD portNum)
{
struct hostent *hp;
unsigned int addr;
struct sockaddr_in server;
SOCKET conn;
conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (conn == INVALID_SOCKET)
return NULL;
if(inet_addr(szServerName)==INADDR_NONE)
{
hp=gethostbyname(szServerName);
}
else
{
addr=inet_addr(szServerName);
hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
}
if(hp==NULL)
{
closesocket(conn);
return NULL;
}
server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
server.sin_family=AF_INET;
server.sin_port=htons(portNum);
if(connect(conn,(struct sockaddr*)&server,sizeof(server)))
{
closesocket(conn);
return NULL;
}
return conn;
}
int getHeaderLength(char *content)
{
const char *srchStr1 = "\r\n\r\n", *srchStr2 = "\n\r\n\r";
char *findPos;
int ofset = -1;
findPos = strstr(content, srchStr1);
if (findPos != NULL)
{
ofset = findPos - content;
ofset += strlen(srchStr1);
}
else
{
findPos = strstr(content, srchStr2);
if (findPos != NULL)
{
ofset = findPos - content;
ofset += strlen(srchStr2);
}
}
return ofset;
}
char *readUrl2(char *szUrl, long &bytesReturnedOut, char **headerOut)
{
const int bufSize = 512;
char readBuffer[bufSize], sendBuffer[bufSize], tmpBuffer[bufSize];
char *tmpResult=NULL, *result;
SOCKET conn;
string server, filepath, filename;
long totalBytesRead, thisReadSize, headerLen;
mParseUrl(szUrl, server, filepath, filename);
///////////// step 1, connect //////////////////////
conn = connectToServer((char*)server.c_str(), 80);
///////////// step 2, send GET request /////////////
sprintf(tmpBuffer, "GET %s HTTP/1.0", filepath.c_str());
strcpy(sendBuffer, tmpBuffer);
strcat(sendBuffer, "\r\n");
sprintf(tmpBuffer, "Host: %s", server.c_str());
strcat(sendBuffer, tmpBuffer);
strcat(sendBuffer, "\r\n");
strcat(sendBuffer, "\r\n");
send(conn, sendBuffer, strlen(sendBuffer), 0);
// SetWindowText(edit3Hwnd, sendBuffer);
printf("Buffer being sent:\n%s", sendBuffer);
///////////// step 3 - get received bytes ////////////////
// Receive until the peer closes the connection
totalBytesRead = 0;
while(1)
{
memset(readBuffer, 0, bufSize);
thisReadSize = recv (conn, readBuffer, bufSize, 0);
if ( thisReadSize <= 0 )
break;
tmpResult = (char*)realloc(tmpResult, thisReadSize+totalBytesRead);
memcpy(tmpResult+totalBytesRead, readBuffer, thisReadSize);
totalBytesRead += thisReadSize;
}
headerLen = getHeaderLength(tmpResult);
long contenLen = totalBytesRead-headerLen;
result = new char[contenLen+1];
memcpy(result, tmpResult+headerLen, contenLen);
result[contenLen] = 0x0;
char *myTmp;
myTmp = new char[headerLen+1];
strncpy(myTmp, tmpResult, headerLen);
myTmp[headerLen] = NULL;
delete(tmpResult);
*headerOut = myTmp;
bytesReturnedOut = contenLen;
closesocket(conn);
return(result);
}

Segfault submitting query

I'm testing a wrapper library for the MySQL C API, and I'm trying to insert a row.
I've tested it in GDB, and the line (in my code) that faults appears as follows:
Breakpoint 1, cq_query (con=0x7fffffffe1c0,
query=0x6014a0 "INSERT INTO TaskType(state,parentID,displayName) VALUES(1,19,'boop')") at cqstatic.c:32
32 return mysql_query(con->con, query);
This query string is formatted correctly (I can paste it into the mysql command line, and it runs fine), so it would appear that something is wrong in the connection (con->con is of type void * cast to MYSQL *).
My other functions which do SELECT and UPDATE work fine. Only insert appears to be broken.
Here is my Test Code
#include <stdio.h>
#include <string.h>
#include <cquel.h>
int main(void)
{
struct dbconn con = cq_new_connection("myurl.tld",
"myuser", "mypasswd", "mydb");
cq_init(1024, 128);
char *fields[] = {
"state",
"parentID",
"displayName"
};
char *vals[] = {
"1",
"19",
"boop"
};
struct drow *row = cq_new_drow(3);
cq_drow_set(row, vals);
struct dlist *list = cq_new_dlist(3, fields, "");
cq_dlist_add(list, row);
cq_insert(con, "TaskType", list);
cq_free_dlist(list);
return 0;
}
Insert Function
int cq_insert(struct dbconn con, const char *table, const struct dlist *list)
{
int rc;
char *query, *columns, *values;
const char *fmt = "INSERT INTO %s(%s) VALUES(%s)";
if (table == NULL)
return 1;
if (list == NULL)
return 2;
query = calloc(CQ_QLEN, sizeof(char));
if (query == NULL)
return -1;
columns = calloc(CQ_QLEN/2, sizeof(char));
if (columns == NULL) {
free(query);
return -2;
}
values = calloc(CQ_QLEN/2, sizeof(char));
if (values == NULL) {
free(query);
free(columns);
return -3;
}
rc = cq_dlist_fields_to_utf8(&con, columns, CQ_QLEN/2, *list);
if (rc) {
free(query);
free(columns);
free(values);
return 100;
}
rc = cq_connect(&con);
if (rc) {
free(query);
free(columns);
free(values);
return 200;
}
for (struct drow *r = list->first; r != NULL; r = r->next) {
rc = cq_drow_to_utf8(&con, values, CQ_QLEN/2, *r);
if (rc)
break;
rc = snprintf(query, CQ_QLEN, fmt, table, columns, values);
if (CQ_QLEN <= (size_t) rc) {
rc = -4;
break;
}
rc = cq_query(&con, query);
if (rc) {
rc = 201;
break;
}
}
cq_close_connection(&con);
free(query);
free(columns);
free(values);
return rc;
}
And one of the important helper functions
int cq_fields_to_utf8(struct dbconn *con, char *buf, size_t buflen,
size_t fieldc, char * const *fieldnames, bool usequotes)
{
int rc = 0;
size_t num_left = fieldc, written = 0;
if (num_left == 0)
return 1;
char *temp = calloc(CQ_FMAXLEN+3, sizeof(char));
if (NULL == temp)
return -1;
char *field = calloc((CQ_FMAXLEN+3)*2+1, sizeof(char));
if (NULL == field) {
free(temp);
return -2;
}
/* prevent appending to buffer */
buf[0] = '\0';
cq_connect(con);
for (size_t i = 0; i < fieldc; ++i) {
bool escaped = fieldnames[i][0] == '\\';
const char *orig = escaped ? &fieldnames[i][1] : fieldnames[i];
const char *value;
bool isstr = false;
if (!escaped) {
mysql_real_escape_string(con->con, field, orig, strlen(orig));
value = field;
if (usequotes)
for (size_t j = 0; j < strlen(value); ++j) {
if (!isdigit(value[j])) {
isstr = true;
break;
}
}
} else {
value = orig;
}
const char *a = isstr ? "'" : "";
const char *c = --num_left > 0 ? "," : "";
written += snprintf(temp, CQ_FMAXLEN+3, "%s%s%s%s", a, value, a, c);
if (written >= buflen) {
rc = 2;
break;
}
strcat(buf, temp);
}
cq_close_connection(con);
free(field);
free(temp);
return rc;
}
used when setting up the query string.
Found my own issue. Blame the 10 minute rule.
I didn't look closely enough at cq_insert(), and it is making a double connection, closing the second one, leaving the first one lost, and the pointer pointing to freed memory, so segfault.

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.

Sending Data to WEB server: Data is being sent, but only once

This code sends data to my server, where it is being get with php and sent to mysql.
The main problem is, that I use cycle void loop(), but it does its task only once. If I will reset the Arduino, then it sends data twice and so on.. I have tried to to send multiple data with delays without a cycle, but it repeatedly sends data, that was send first.. Help :)
#include <SPI.h>
#include <Ethernet.h>
#include <stdlib.h> //Including libraries
int moi_int = 12;
int temp_int = 13; //doing some convertion
int moi_int1 = moi_int %10;
int moi_int2 = moi_int - moi_int1;
int moi_int3 = moi_int2/10;
char moi1 = (char)(((int)'0')+moi_int1);
char moi2 = (char)(((int)'0')+moi_int3);
int temp_int1 = temp_int %10;
int temp_int2 = temp_int - temp_int1;
int temp_int3 = temp_int2/10;
char temp1 = (char)(((int)'0')+temp_int1); //convertion
char temp2 = (char)(((int)'0')+temp_int3);
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte server[] = { my server };
IPAddress ip(my ip);
EthernetClient client;
void setup() {
Serial.begin(9600);
}
void SendInfo() //Info
{
char string[29]; //Here is displayed by char some adress (data) I need to send
string[0] = 'G'; string[1] = 'E'; string[2] = 'T'; string[3] = ' '; string[4] = '/'; string[5] = 'a'; string[6] = 'd'; string[7] = 'd';
string[8] = '.'; string[9] = 'p'; string[10] = 'h'; string[11] = 'p'; string[12] = '?'; string[13] = 't'; string[14] = 'e'; string[15] = 'm';
string[16] = 'p'; string[17] = '1'; string[18] = '='; string[19] = temp2; string[20] = temp1; string[21] = '&'; string[22] = '&';
string[23] = 'm'; string[24] = 'o'; string[25] = 'i'; string[26] = '1'; string[27] = '='; string[28] = moi2; string[29] = moi1;
String adresas(string);
client.println(adresas); // Sending Data
client.print(" HTTP/1.1");
client.println( "Host: my server" );
client.println("Connection: close");
client.println();
}
void Connect() //Connecting
{
Ethernet.begin(mac, ip);
delay(1000);
if (client.connect(server, 80)) {
delay(1000);
SendInfo();
delay(1000);
}
else Serial.println("connection failed");
}
void loop() //Main Loop
{
Connect();
}
You should call begin() only once in the setup:
void setup() {
...
Ethernet.begin()
You call
client.connect(server, 80)
but never a matching disconnect. You need to add one of these to cleanup the connection:
if (client.connect(server, 80)) {
...
client.stop();
}
An alternate approach is to re-user the previously opened connection on each loop.
// open the connection if needed
if(!client.connected()) {
client.connect(server, 80);
}
// ensure connection is available before trying to write
if(client.connected()) {
// do something with connection
}
If you are going to be transmitting very frequent small data, then this second approach is better because less time is wasted to the open/close of the connection.