#include #include #include #define NAME "sql_printf" #define N_ARGS 1 #define BLOCK_SIZE 1024 extern "C" { typedef struct { int * org_type; char * data; unsigned long len; unsigned long alloc; } Buffer; static void buffer_append_len(Buffer *buffer, const char *string, unsigned long len) { if (!string) return; unsigned long new_len = buffer->len + len; if (new_len > buffer->alloc) { buffer->alloc = new_len + BLOCK_SIZE - (new_len % BLOCK_SIZE); buffer->data = (char *) realloc(buffer->data, sizeof(char) * buffer->alloc); } strncpy(&buffer->data[buffer->len], string, len); buffer->len = new_len; } static void buffer_append(Buffer *buffer, const char *string) { if (!string) return; buffer_append_len(buffer, string, strlen(string)); } char * sql_printf(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) { unsigned int i = 1; unsigned long j = 0; Buffer *buffer = (Buffer *) initid->ptr; char *format = args->args[0]; if (!format) { *is_null = 1; return NULL; } while (1) { const char *delimiter = NULL; unsigned long aux = j; while (j < args->lengths[0] && format[j] != '%') j++; buffer_append_len(buffer, &format[aux], j - aux); if (j == args->lengths[0]) break; char c = format[j+1]; j += 2; switch (c) { case 't': delimiter = "`"; break; case 'v': if (buffer->org_type[i] == STRING_RESULT) delimiter = "'"; break; case 's': break; case '%': buffer_append(buffer, "%"); continue; default: *error = 1; return NULL; } if (i >= args->arg_count) { *error = 1; return NULL; } char *arg = args->args[i]; if (arg != NULL) { buffer_append(buffer, delimiter); buffer_append_len(buffer, arg, args->lengths[i]); buffer_append(buffer, delimiter); } else buffer_append(buffer, "NULL"); i++; } *length = buffer->len; return buffer->data; } bool sql_printf_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { if (args->arg_count >= N_ARGS) { unsigned int i; Buffer *buffer = (Buffer *) malloc(sizeof(Buffer)); buffer->org_type = (int *) malloc(sizeof(int) * args->arg_count); buffer->alloc = BLOCK_SIZE; buffer->data = (char *) malloc(sizeof(char) * buffer->alloc); buffer->len = 0; for (i = 0; i < args->arg_count; i++) { buffer->org_type[i] = args->arg_type[i]; args->arg_type[i] = STRING_RESULT; } initid->ptr = (char *) buffer; initid->maybe_null = 1; initid->const_item = 0; return 0; } else { sprintf(message, "%s must have at least %d parameters", NAME, N_ARGS); return 1; } } void sql_printf_deinit(UDF_INIT *initid) { Buffer *buffer = (Buffer *) initid->ptr; free(buffer->org_type); free(buffer->data); free(buffer); } }