minimum-viable MySQL connector

This commit is contained in:
Udo 2021-12-01 01:38:19 +00:00
parent a5d63ce3f0
commit 740dc28b11
5 changed files with 212 additions and 31 deletions

Binary file not shown.

View File

@ -49,6 +49,7 @@ struct DTree {
string _string;
f64 _float;
s64 _array_index;
bool _bool;
void* _ptr;
std::map<string, DTree> _map;
@ -88,7 +89,7 @@ struct DTree {
return(_bool ? "(true)" : "(false)");
break;
case('M'):
return("(array)");
return("");
break;
case('P'):
return(std::to_string((u64)_ptr));
@ -140,37 +141,48 @@ struct DTree {
}
}
void set_type(char t)
{
if(type != t)
{
type = t;
switch(type)
{
case('M'):
_map.clear();
_array_index = 0;
break;
}
}
}
void set(string s)
{
if(type == 'M') _map.clear();
type = 'S';
set_type('S');
_string = s;
}
void set(void* p)
{
if(type == 'M') _map.clear();
type = 'P';
set_type('P');
_ptr = p;
}
void set(f64 f)
{
if(type == 'M') _map.clear();
type = 'F';
set_type('F');
_float = f;
}
void set_bool(bool b)
{
if(type == 'M') _map.clear();
type = 'B';
set_type('B');
_bool = b;
}
void set(DTree source)
{
type = source.type;
set_type(source.type);
switch(type)
{
case('S'):
@ -193,8 +205,7 @@ struct DTree {
void set(StringMap source)
{
type = 'M';
_map.clear();
set_type('M');
for (auto it = source.begin(); it != source.end(); ++it)
{
(*this)[it->first] = it->second;
@ -203,12 +214,12 @@ struct DTree {
DTree* key(string s)
{
type = 'M';
set_type('M');
return(&_map[s]);
}
DTree& operator [] (string s) {
type = 'M';
set_type('M');
return(_map[s]);
}
@ -218,15 +229,31 @@ struct DTree {
void operator = (DTree v) { set(v); }
void operator = (StringMap v) { set(v); }
void push(DTree& child)
{
set_type('M');
_map[std::to_string(_array_index)] = child;
_array_index += 1;
}
DTree pop()
{
set_type('M');
auto last = _map.rbegin();
DTree result = last->second;
_map.erase(last->first);
return(result);
}
void remove(string s)
{
type = 'M';
set_type('M');
_map.erase(s);
}
void clear()
{
type = 'M';
set_type('M');
_map.clear();
}

View File

@ -67,19 +67,118 @@ string MySQL::escape(string raw, char quote_char)
return(result);
}
bool MySQL::query(string query)
DTree field_to_dtree_node(char* data_ptr, MySQLFieldInfo field_info, u32 len)
{
auto res = mysql_query((MYSQL*)connection, query.c_str());
return(true);
DTree result;
switch(field_info.type)
{
case(MYSQL_TYPE_TINY):
result.set(atoll(data_ptr));
break;
case(MYSQL_TYPE_SHORT):
result.set(atoll(data_ptr));
break;
case(MYSQL_TYPE_LONG):
result.set(atoll(data_ptr));
break;
case(MYSQL_TYPE_INT24):
result.set(atoll(data_ptr));
break;
case(MYSQL_TYPE_LONGLONG):
result.set(atoll(data_ptr));
break;
case(MYSQL_TYPE_FLOAT):
result.set(atof(data_ptr));
break;
case(MYSQL_TYPE_DOUBLE):
result.set(atof(data_ptr));
break;
case(MYSQL_TYPE_NULL):
break;
default:
string s;
s.assign(data_ptr);
result.set(s);
break;
}
return(result);
}
bool MySQL::query(string query, StringMap params)
DTree MySQL::get_pending_result()
{
auto res = mysql_query(
(MYSQL*)connection,
parse_query_parameters(query, params).c_str()
);
return(true);
DTree result_data;
// based on: https://dev.mysql.com/doc/c-api/5.7/en/mysql-field-count.html
MYSQL_RES *result;
result = mysql_store_result((MYSQL*)connection);
insert_id = mysql_insert_id((MYSQL*)connection);
//statement_info.assign(mysql_info((MYSQL*)connection));
if (result) // there are rows
{
field_count = mysql_num_fields(result);
row_count = mysql_num_rows(result);
field_info.clear();
unsigned int i;
MYSQL_FIELD *fields;
fields = mysql_fetch_fields(result);
for(i = 0; i < field_count; i++)
{
MySQLFieldInfo fi;
if(fields[i].name) fi.name.assign(fields[i].name);
if(fields[i].table) fi.table.assign(fields[i].table);
if(fields[i].db) fi.db.assign(fields[i].db);
fi.length = (fields[i].length);
if(fields[i].def) fi.def.assign(fields[i].def);
fi.max_length = (fields[i].max_length);
fi.flags = (fields[i].flags);
fi.type = (fields[i].type);
field_info.push_back(fi);
}
MYSQL_ROW row;
while ((row = mysql_fetch_row(result)))
{
DTree row_data;
auto lengths = mysql_fetch_lengths(result);
for(i = 0; i < field_count; i++)
{
row_data[field_info[i].name] = field_to_dtree_node(row[i], field_info[i], lengths[i]);
}
result_data.push(row_data);
}
mysql_free_result(result);
}
else // mysql_store_result() returned nothing; should it have?
{
if(mysql_field_count((MYSQL*)connection) == 0)
{
// query does not return data
// (it was not a SELECT)
affected_rows = mysql_affected_rows((MYSQL*)connection);
}
else // mysql_store_result() should have returned data
{
// error
}
}
return(result_data);
}
DTree MySQL::query(string q)
{
_preload_next_error_code = mysql_query((MYSQL*)connection, q.c_str());
DTree result;
if(_preload_next_error_code == 0)
result = get_pending_result();
return(result);
}
DTree MySQL::query(string q, StringMap params)
{
return(query(
parse_query_parameters(q, params).c_str()
));
}
string MySQL::parse_query_parameters(string query, StringMap map)
@ -144,6 +243,31 @@ void MySQL::disconnect()
string MySQL::error()
{
if(_preload_next_error_code)
{
string p = "Unknown error";
switch(_preload_next_error_code)
{
case(CR_COMMANDS_OUT_OF_SYNC):
p = "Commands out of sync";
break;
case(CR_SERVER_GONE_ERROR):
p = "Server connection error";
break;
case(CR_SERVER_LOST):
p = "Server hung up";
break;
case(CR_OUT_OF_MEMORY):
p = "Out of memory";
break;
default:
case(CR_UNKNOWN_ERROR):
p = "Unknown server error";
break;
}
_preload_next_error_code = 0;
return(p);
}
const char* res = mysql_error((MYSQL*)connection);
if(res)
{

View File

@ -1,14 +1,33 @@
struct MySQLFieldInfo {
string name;
string table;
string db;
u64 length;
string def;
u64 max_length;
u64 flags;
u32 type;
};
struct MySQL {
void* connection;
void* connection = 0;
u32 _preload_next_error_code = 0;
u32 affected_rows = 0;
u32 field_count = 0;
u32 row_count = 0;
u64 insert_id = 0;
string statement_info = "";
std::vector<MySQLFieldInfo> field_info;
bool connect(string host = "localhost", string username = "root", string password = "");
void disconnect();
string error();
string escape(string raw, char quote_char = '\'');
string parse_query_parameters(string query, StringMap m);
bool query(string query);
bool query(string query, StringMap params);
DTree query(string q);
DTree query(string q, StringMap params);
DTree get_pending_result();
};

View File

@ -19,14 +19,25 @@ RENDER()
params["val"] = "Dubious\\Value'Name\nwith;breaks";
MySQL con;
if(con.connect("localhost", "root", "q831b197f"))
if(con.connect("localhost", "root", ""))
{
echo("connection established\n");
echo("error: "+con.error()+"\n");
echo("quotation test: "+con.escape("\"' or 1=1;.")+"\n");
echo("query parse: "+con.parse_query_parameters(query, params)+"\n");
echo(var_dump(con.query("SHOW DATABASES")));
con.query("USE mysql");
?></pre>
SELECT * FROM user table
<pre><?
echo(var_dump(con.query("SELECT * FROM user")));
}
?></pre>
<label>CGI Params</label>