functions for multi-row insert
authorMiloš Mulač <mulac@civ.zcu.cz>
Mon, 26 Jun 2006 13:56:21 +0000 (13:56 +0000)
committerMiloš Mulač <mulac@civ.zcu.cz>
Mon, 26 Jun 2006 13:56:21 +0000 (13:56 +0000)
- needs a bit more flesh to work

org.glite.lb.server/interface/lbs_db.h
org.glite.lb.server/src/lbs_db.c

index 14dbad8..df557c0 100644 (file)
@@ -12,7 +12,9 @@
 extern "C" {
 #endif
 
-#define EDG_WLL_MYSQL_VERSION  40001
+#define EDG_WLL_MYSQL_VERSION          40001
+#define BUF_INSERT_ROW_ALLOC_BLOCK     1000
+
 
 typedef struct _edg_wll_Stmt *edg_wll_Stmt;
 
@@ -21,6 +23,27 @@ edg_wll_ErrorCode edg_wll_DBConnect(
        char *          /* IN: connect string user/password@host:database */
 );
 
+
+/*
+ * structure holds date for multi-rows insert
+ */
+typedef struct _edg_wll_bufInsert {
+       edg_wll_Context ctx;
+       char    *table_name;
+       int     num_cols;
+       char    **columns;      /* names of columns to be inserted into */
+       long    rec_num,        /* actual number of rows in structure */
+               rec_size;       /* approx. size of a real insert string */
+       long    *row_len;       /* array holding length of each row */
+       long    *row_alloc;     /* size of allocated space for each row */
+       char    **values;       /* each row hold long string with values
+                                * inserting into one column separated with 
+                                * commas */
+       long    size_limit,     /* size and # of records limit which trigger */
+               record_limit;   /* real insert; zero means unlimitted */
+} edg_wll_bufInsert;
+
+
 void edg_wll_DBClose(edg_wll_Context);
 
 
@@ -84,6 +107,29 @@ int edg_wll_Transaction(edg_wll_Context ctx);
 int edg_wll_Commit(edg_wll_Context ctx);
 int edg_wll_Rollback(edg_wll_Context ctx);
 
+/**
+ * Init data structure for buffered insert
+ *
+ * takes num_cols string parameters as names of columns to be inserted into
+ * when insert string oversize size_limit or number of rows to be inserted
+ * overcome record_limit, the real insert is triggered
+ */
+int edg_wll_bufferedInsertInit(edg_wll_Context ctx, edg_wll_bufInsert *bi, void *mysql, char *table_name, long size_limit, long record_limit, int num_cols, ...);
+
+/**
+ * adds row of n values into n columns into an insert buffer
+ * if num. of rows or size of data oversteps the limits, real
+ * multi-row insert is done
+ */
+edg_wll_ErrorCode edg_wll_bufferedInsert(edg_wll_bufInsert *bi, ...);
+
+/**
+ * flush buffered data and free bi structure
+ */
+edg_wll_ErrorCode edg_wll_bufferedInsertClose(edg_wll_bufInsert *bi);
+
+
+
 #ifdef __cplusplus
 }
 #endif
index 0aa72d2..7adf335 100644 (file)
 #include <errno.h>
 #include <sys/types.h>
 #include <time.h>
+#include <assert.h>
+#include <stdarg.h>
 
 #include "lbs_db.h"
 #include "glite/lb/context-int.h"
+#include "glite/lb/trio.h"
 
 
 #define DEFAULTCS      "lbserver/@localhost:lbserver20"
@@ -266,3 +269,154 @@ int edg_wll_Rollback(edg_wll_Context ctx) {
 
        return err;
 }
+
+
+int edg_wll_bufferedInsertInit(edg_wll_Context ctx, edg_wll_bufInsert *bi, void *mysql, char *table_name, long size_limit, long record_limit, int num_cols, ...)
+{
+       va_list l;
+       long    i;
+
+
+       assert(num_cols != 1);  // XXX: I do not know one column multi-row insert :(
+       va_start(l, num_cols);
+       
+       bi->ctx = ctx;
+       bi->table_name = strdup(table_name);
+       bi->num_cols = num_cols;
+       bi->columns = calloc(num_cols, sizeof(*(bi->columns)) );
+       bi->rec_num = 0;
+       bi->rec_size = 0;
+       bi->row_len = calloc(num_cols, sizeof(*(bi->row_len)) );
+       bi->row_alloc = calloc(num_cols, sizeof(*(bi->row_alloc)) );
+       bi->values = calloc(num_cols, sizeof(*(bi->values)) );
+       bi->size_limit = size_limit;
+       bi->record_limit = record_limit;
+
+       for (i=0; i < num_cols; i++) {
+               bi->columns[i] = strdup(va_arg(l,char *));      
+               bi->row_len[i] = 0;
+               bi->row_alloc[i] = 0;
+       }
+
+       va_end(l);
+       return 0;
+}
+
+
+
+static int string_add(char *what, long *used_size, long *alloc_size, char **where)
+{
+       long    what_len = strlen(what);
+       int     reall = 0;
+
+       while (*used_size + what_len >= *alloc_size) {
+               *alloc_size += BUF_INSERT_ROW_ALLOC_BLOCK;
+               reall = 1;
+       }
+
+       if (reall) 
+               *where = realloc(*where, *alloc_size * sizeof(char));
+
+       what_len = sprintf(*where + *used_size, "%s", what);
+       if (what_len < 0) /* ENOMEM? */ return -1;
+
+       *used_size += what_len;
+
+       return 0;
+}
+
+
+static int flush_bufferd_insert(edg_wll_bufInsert *bi)
+{
+       char *stmt, *cols, *vals, *temp;
+       long i;
+
+       asprintf(&cols,"%s", bi->columns[0]);
+       asprintf(&vals,"%s", bi->values[0]);
+       for (i=1; i < bi->num_cols; i++) {
+               asprintf(&temp,"%s,%s", cols, bi->columns[i]);
+               free(cols); cols = temp; temp = NULL;
+               asprintf(&temp,"%s),(%s", vals, bi->values[i]);
+               free(vals); vals = temp; temp = NULL;
+               
+       }
+       
+       trio_asprintf(&stmt, "insert into %|Ss(%|Ss) values (%|Ss);",
+               bi->table_name, cols, vals);
+
+       // XXX:fire statement, check result, check errors
+       printf("\n%s\n",stmt);
+
+       /* reset bi counters */
+       bi->rec_size = 0;
+       bi->rec_num = 0;
+       for (i=0; i < bi->num_cols; i++) 
+               bi->row_len[i] = 0;
+       
+       free(cols);
+       free(vals);
+       free(stmt);
+
+       return 0;
+}
+
+
+/*
+ * adds row of n values into n columns into an insert buffer
+ * if num. of rows or size of data oversteps the limits, real
+ * multi-row insert is done
+ */
+edg_wll_ErrorCode edg_wll_bufferedInsert(edg_wll_bufInsert *bi, ...)
+{
+       va_list l;
+       long    i;
+
+
+       va_start(l, bi);
+
+       bi->rec_size = 0;
+       for (i=0; i < bi->num_cols; i++) {
+               if (bi->rec_num) { 
+                       if (string_add(",", &bi->row_len[i], &bi->row_alloc[i], &bi->values[i]))
+                               return edg_wll_SetError(bi->ctx,ENOMEM,NULL);;
+               }
+               if (string_add(va_arg(l,char *), &bi->row_len[i], &bi->row_alloc[i], &bi->values[i]))
+                       return edg_wll_SetError(bi->ctx,ENOMEM,NULL);;
+               bi->rec_size += bi->row_len[i];
+       }
+       bi->rec_num++;
+
+       if ((bi->size_limit && bi->rec_size >= bi->size_limit) ||
+               (bi->record_limit && bi->rec_num >= bi->record_limit))
+       {
+               if (flush_bufferd_insert(bi))
+                       return -1;      // XXX use edg_wll_SetError(something)
+       }
+
+       va_end(l);
+       return edg_wll_ResetError(bi->ctx);
+}
+
+static void free_buffered_insert(edg_wll_bufInsert *bi) {
+       long i;
+       
+       free(bi->table_name);
+       for (i=0; i < bi->num_cols; i++) {
+               free(bi->columns[i]);
+               free(bi->values[i]);
+       }
+       free(bi->columns);
+       free(bi->values);
+       free(bi->row_len);
+       free(bi->row_alloc);
+}
+
+edg_wll_ErrorCode edg_wll_bufferedInsertClose(edg_wll_bufInsert *bi)
+{
+       if (flush_bufferd_insert(bi))
+               return -1;      // XXX use edg_wll_SetError(something)
+       free_buffered_insert(bi);
+
+       return edg_wll_ResetError(bi->ctx);
+}
+