#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>

void connect_and_prepare(MYSQL *c, uint8_t *blob) {
	int rc;
	char buf[2048];

	mysql_options(c, MYSQL_SET_CHARSET_NAME, "utf8");

	if (!mysql_real_connect(c, "127.0.0.1", "root", "secret", "testing", 3306, NULL, 0)) {
		fprintf(stderr, "error connecting to the server: %s\n", mysql_error(c));
		exit(1);
	}

	if (mysql_query(c, "CREATE TABLE IF NOT EXISTS x (b VARBINARY(16) NOT NULL, PRIMARY KEY (b))")) {
		fprintf(stderr, "error creating table: %s\n",  mysql_error(c));
		exit(1);
	}

	int n = 0;
	n += sprintf(buf+n, "INSERT IGNORE INTO x VALUES(0x");
	for (int i = 0; blob[i]; i++) {
		n += sprintf(buf+n, "%02X", blob[i]);
	}
	n += sprintf(buf+n, ")");

	printf("%s\n", buf);
	if (mysql_query(c, buf)) {
		fprintf(stderr, "error inserting dummy value: %s\n",  mysql_error(c));
		exit(1);
	}
}

void read_blob(MYSQL *c, uint8_t *blob, int count) {
	MYSQL_STMT *s;

	s = mysql_stmt_init(c);
	if (!s) {
		fprintf(stderr, "error allocating prepared statement\n");
		exit(1);
	}

	unsigned long len = 0;
	for (len = 0; blob[len]; len++);

	MYSQL_BIND bind[count];
	memset(bind, 0, sizeof(bind));
	char buf[4096];
	int n = 0;
	n += sprintf(buf+n, "SELECT b FROM x WHERE b IN (");
	for (int i = 0; i < count; i ++) {
		n += sprintf(buf+n, "?,");
		bind[i].buffer_type = MYSQL_TYPE_STRING;
		bind[i].buffer = (void *)blob;
		bind[i].buffer_length = len+1;
		bind[i].length = &len;
		bind[i].is_null = (my_bool*) 0;
		bind[i].is_unsigned = 0;
	}
	n--; // drop trailing ','
	n += sprintf(buf+n, ")");
	//printf("%s\n", buf);

	if(mysql_stmt_prepare(s, buf, n)) {
		fprintf(stderr, "error creating prepared statement: %s\n", mysql_error(c));
		exit(1);
	}

	if(mysql_stmt_bind_param(s, bind)) {
		fprintf(stderr, "error binding prepared statement input: %s\n", mysql_error(c));
		exit(1);
	}
	if(mysql_stmt_execute(s)) {
		fprintf(stderr, "error executing prepared statement: %s\n", mysql_error(c));
		exit(1);
	}

	MYSQL_BIND out;
	uint8_t out_blob[1024];
	unsigned long out_len;
	my_bool is_null;
	my_bool error;
	memset(&out, 0 , sizeof(out));
	out.buffer_type = MYSQL_TYPE_BLOB;
	out.buffer = out_blob;
	out.is_null = &is_null;
	out.length = &out_len;
	out.error = &error;

	if (mysql_stmt_bind_result(s, &out)) {
		fprintf(stderr, "error binding prepared statement output: %s\n", mysql_error(c));
		exit(1);
	}

	while (1) {
		int status = mysql_stmt_fetch(s);
		if (status == 1) {
			printf("error fetching row: %s\n", mysql_stmt_error(s));
			break;
		}
		if (status == MYSQL_NO_DATA) {
			break;
		}
		printf("count %d, blob: ", count);
		for (int i = 0; i < out_len; i++) {
			printf("%02x", blob[i]);
		}
		printf("\n");
	}

	mysql_stmt_close(s);
}

int main(int argc, char **argv) {
	MYSQL c;
	int rc;

	if (mysql_library_init(0, NULL, NULL)) {
		fprintf(stderr, "error initializing mysql library\n");
		exit(1);
	}

	if (!mysql_init(&c)) {
		fprintf(stderr, "error allocating mysql handler\n");
		exit(1);
	}


	uint8_t blob[] = {255, 0};
	connect_and_prepare(&c, blob);

	read_blob(&c, blob, 999);
	read_blob(&c, blob, 1000);

	mysql_close(&c);
	mysql_library_end();
	return EXIT_SUCCESS;
}
