377 lines
8.1 KiB
C
377 lines
8.1 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <mysql.h>
|
|
|
|
#include "db_column.h"
|
|
#include "strext.h"
|
|
|
|
|
|
size_t columnTypeToByteSize(e_column_type type)
|
|
{
|
|
switch(type) {
|
|
case TYPE_BOOL:
|
|
return sizeof(uint8_t);
|
|
|
|
case TYPE_INT8:
|
|
case TYPE_UINT8:
|
|
return sizeof(uint8_t);
|
|
|
|
case TYPE_INT16:
|
|
case TYPE_UINT16:
|
|
return sizeof(uint16_t);
|
|
|
|
case TYPE_INT32:
|
|
case TYPE_UINT32:
|
|
return sizeof(uint32_t);
|
|
|
|
case TYPE_INT64:
|
|
case TYPE_UINT64:
|
|
return sizeof(uint64_t);
|
|
|
|
case TYPE_FLOAT:
|
|
return sizeof(float);
|
|
case TYPE_DOUBLE:
|
|
return sizeof(double);
|
|
|
|
case TYPE_STRING:
|
|
return sizeof(char *);
|
|
case TYPE_BLOB:
|
|
return sizeof(char *);
|
|
|
|
case TYPE_TIMESTAMP:
|
|
return sizeof(uint32_t);
|
|
|
|
case TYPE_RAW:
|
|
return sizeof(char *);
|
|
}
|
|
return sizeof(char *);
|
|
}
|
|
|
|
e_column_type simplifyFieldType(enum enum_field_types sql_type, int is_unsigned)
|
|
{
|
|
switch(sql_type) {
|
|
case MYSQL_TYPE_TINY:
|
|
return is_unsigned ? TYPE_UINT8 : TYPE_INT8;
|
|
|
|
case MYSQL_TYPE_SHORT:
|
|
return is_unsigned ? TYPE_UINT16 : TYPE_INT16;
|
|
|
|
case MYSQL_TYPE_LONG:
|
|
case MYSQL_TYPE_INT24:
|
|
return is_unsigned ? TYPE_UINT32 : TYPE_INT32;
|
|
|
|
case MYSQL_TYPE_LONGLONG:
|
|
case MYSQL_TYPE_BIT:
|
|
return is_unsigned ? TYPE_UINT64 : TYPE_INT64;
|
|
|
|
case MYSQL_TYPE_FLOAT:
|
|
return TYPE_FLOAT;
|
|
|
|
case MYSQL_TYPE_DOUBLE:
|
|
return TYPE_DOUBLE;
|
|
|
|
case MYSQL_TYPE_TIMESTAMP:
|
|
case MYSQL_TYPE_TIMESTAMP2:
|
|
return TYPE_TIMESTAMP;
|
|
|
|
case MYSQL_TYPE_VAR_STRING:
|
|
case MYSQL_TYPE_STRING:
|
|
case MYSQL_TYPE_VARCHAR:
|
|
return TYPE_STRING;
|
|
|
|
case MYSQL_TYPE_JSON:
|
|
case MYSQL_TYPE_TINY_BLOB:
|
|
case MYSQL_TYPE_MEDIUM_BLOB:
|
|
case MYSQL_TYPE_LONG_BLOB:
|
|
case MYSQL_TYPE_BLOB:
|
|
return TYPE_BLOB;
|
|
|
|
case MYSQL_TYPE_YEAR:
|
|
|
|
case MYSQL_TYPE_DATE:
|
|
case MYSQL_TYPE_NEWDATE:
|
|
|
|
case MYSQL_TYPE_TIME:
|
|
case MYSQL_TYPE_TIME2:
|
|
|
|
case MYSQL_TYPE_DATETIME:
|
|
case MYSQL_TYPE_DATETIME2:
|
|
|
|
case MYSQL_TYPE_SET:
|
|
case MYSQL_TYPE_ENUM:
|
|
case MYSQL_TYPE_NEWDECIMAL:
|
|
case MYSQL_TYPE_DECIMAL:
|
|
case MYSQL_TYPE_GEOMETRY:
|
|
case MYSQL_TYPE_NULL:
|
|
default:
|
|
return TYPE_RAW;
|
|
}
|
|
}
|
|
|
|
|
|
struct column_data_t *initEmptyColumn(e_column_type type, int nullable, const char *name,
|
|
size_t name_len, const char *table, size_t table_len)
|
|
{
|
|
struct column_data_t *col;
|
|
|
|
if (name_len == 0) {
|
|
name_len = strlen(name);
|
|
}
|
|
|
|
col = (struct column_data_t *)malloc(sizeof(struct column_data_t));
|
|
if (col == NULL) {
|
|
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
|
return 0;
|
|
}
|
|
memset(col, 0, sizeof(struct column_data_t));
|
|
|
|
if (strmemcpy(name, name_len, &col->name, &col->name_len) != 0) {
|
|
free(col);
|
|
return 0;
|
|
}
|
|
|
|
if (table != 0) {
|
|
if (strmemcpy(table, table_len, &col->table, &col->table_len) != 0) {
|
|
free(col->name);
|
|
free(col);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
col->type = type;
|
|
col->type_bytes = columnTypeToByteSize(col->type);
|
|
|
|
col->n_values = 0;
|
|
|
|
col->hasPointers = col->type == TYPE_STRING
|
|
|| col->type == TYPE_BLOB
|
|
|| col->type == TYPE_RAW;
|
|
col->isUnsigned = col->type == TYPE_UINT8
|
|
|| col->type == TYPE_UINT16
|
|
|| col->type == TYPE_UINT32
|
|
|| col->type == TYPE_UINT64;
|
|
col->isNullable = nullable > 0;
|
|
col->isBlob = type == TYPE_BLOB;
|
|
col->isTimestamp = type == TYPE_TIMESTAMP;
|
|
|
|
return col;
|
|
}
|
|
|
|
struct column_data_t *columnFromResult(struct stored_conn_t *sconn, MYSQL_RES *result,
|
|
uint64_t num_rows)
|
|
{
|
|
MYSQL_FIELD *field;
|
|
struct column_data_t *col;
|
|
|
|
field = mysql_fetch_field(result);
|
|
if (field == NULL) {
|
|
fprintf(
|
|
stderr, "[%d]mysql_fetch_field: (%d) %s\n",
|
|
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
col = initEmptyColumn(
|
|
simplifyFieldType(field->type, (field->flags & UNSIGNED_FLAG) > 0),
|
|
(field->flags & NOT_NULL_FLAG) == 0,
|
|
field->name,
|
|
field->name_length,
|
|
field->table,
|
|
field->table_length
|
|
);
|
|
|
|
if (col == 0 || num_rows == 0) {
|
|
return col;
|
|
}
|
|
|
|
col->n_values = num_rows;
|
|
|
|
col->data.vptr = malloc(col->type_bytes * num_rows);
|
|
if (col->data.vptr == NULL) {
|
|
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
|
free(col->name);
|
|
free(col);
|
|
return 0;
|
|
}
|
|
memset(col->data.vptr, 0, col->type_bytes * num_rows);
|
|
|
|
if (col->hasPointers) {
|
|
col->data_lens = (size_t *)malloc(sizeof(size_t) * num_rows);
|
|
if (col->data_lens == NULL) {
|
|
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
|
free(col->data.vptr);
|
|
free(col->name);
|
|
free(col);
|
|
return 0;
|
|
}
|
|
memset(col->data_lens, 0, sizeof(size_t) * num_rows);
|
|
}
|
|
|
|
if (col->isNullable) {
|
|
col->nulls = malloc(num_rows / 8 + 1);
|
|
if (col->nulls == NULL) {
|
|
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
|
if (col->data_lens) {
|
|
free(col->data_lens);
|
|
}
|
|
free(col->data.vptr);
|
|
free(col->name);
|
|
free(col);
|
|
return 0;
|
|
}
|
|
memset(col->nulls, 0, num_rows / 8 + 1);
|
|
}
|
|
|
|
return col;
|
|
}
|
|
|
|
void freeColumn(struct column_data_t *col)
|
|
{
|
|
if (col->hasPointers) {
|
|
for (unsigned int r = 0; r < col->n_values; r++) {
|
|
if (!columnRowIsNull(col, r)) {
|
|
free(*(col->data.ptr_str + r));
|
|
*(col->data.ptr_str + r) = 0;
|
|
}
|
|
}
|
|
|
|
free(col->data_lens);
|
|
col->data_lens = 0;
|
|
}
|
|
|
|
if (col->data.vptr) {
|
|
free(col->data.vptr);
|
|
col->data.vptr = 0;
|
|
}
|
|
|
|
if (col->isNullable) {
|
|
free(col->nulls);
|
|
col->nulls = 0;
|
|
}
|
|
|
|
free(col->name);
|
|
col->name = 0;
|
|
|
|
free(col);
|
|
}
|
|
void freeColumns(struct column_data_t **col_data, size_t n_cols)
|
|
{
|
|
for (size_t c = 0; c < n_cols; c++) {
|
|
freeColumn(*(col_data + c));
|
|
}
|
|
free(col_data);
|
|
}
|
|
|
|
|
|
int setColumnValue(struct column_data_t *col, uint64_t row, const char *value, size_t value_size)
|
|
{
|
|
if (value == NULL) {
|
|
columnRowSetNull(col, row);
|
|
return 0;
|
|
}
|
|
|
|
if (value_size == 0) {
|
|
value_size = strlen(value);
|
|
}
|
|
|
|
switch(col->type) {
|
|
case TYPE_BOOL:
|
|
{
|
|
*(col->data.ptr_uint8 + row) = value[0] == '1';
|
|
break;
|
|
}
|
|
|
|
case TYPE_INT8:
|
|
{
|
|
*(col->data.ptr_int8 + row) = (int8_t)strtol(value, NULL, 10);
|
|
break;
|
|
}
|
|
case TYPE_UINT8:
|
|
{
|
|
*(col->data.ptr_uint8 + row) = (uint8_t)strtoul(value, NULL, 10);
|
|
break;
|
|
}
|
|
|
|
case TYPE_INT16:
|
|
{
|
|
*(col->data.ptr_int16 + row) = (int16_t)strtol(value, NULL, 10);
|
|
break;
|
|
}
|
|
case TYPE_UINT16:
|
|
{
|
|
*(col->data.ptr_uint16 + row) = (uint16_t)strtoul(value, NULL, 10);
|
|
break;
|
|
}
|
|
|
|
case TYPE_INT32:
|
|
{
|
|
*(col->data.ptr_int32 + row) = (int32_t)strtol(value, NULL, 10);
|
|
break;
|
|
}
|
|
case TYPE_UINT32:
|
|
{
|
|
*(col->data.ptr_uint32 + row) = (uint32_t)strtoul(value, NULL, 10);
|
|
break;
|
|
}
|
|
|
|
case TYPE_INT64:
|
|
{
|
|
*(col->data.ptr_int64 + row) = strtoll(value, NULL, 10);
|
|
break;
|
|
}
|
|
case TYPE_UINT64:
|
|
{
|
|
*(col->data.ptr_uint64 + row) = strtoull(value, NULL, 10);
|
|
break;
|
|
}
|
|
|
|
case TYPE_FLOAT:
|
|
{
|
|
*(col->data.ptr_float + row) = strtof(value, NULL);
|
|
break;
|
|
}
|
|
case TYPE_DOUBLE:
|
|
{
|
|
*(col->data.ptr_double + row) = strtod(value, NULL);
|
|
break;
|
|
}
|
|
|
|
case TYPE_TIMESTAMP:
|
|
{
|
|
*(col->data.ptr_uint32 + row) = (uint32_t)strtoul(value, NULL, 10);
|
|
break;
|
|
}
|
|
case TYPE_STRING:
|
|
case TYPE_BLOB:
|
|
case TYPE_RAW:
|
|
{
|
|
if (strmemcpy(value, value_size, (col->data.ptr_str + row), (col->data_lens + row)) != 0) {
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct column_data_t *selectColumn(struct column_data_t **col_data, size_t n_cols, const char *name)
|
|
{
|
|
struct column_data_t *col = 0;
|
|
size_t idx = 0;
|
|
size_t name_len = strlen(name);
|
|
|
|
while (idx < n_cols) {
|
|
col = *(col_data + idx);
|
|
if (col->name_len == name_len && strncmp(col->name, name, name_len) == 0) {
|
|
return *(col_data + idx);
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return 0;
|
|
}
|