[Groonga-commit] groonga/groonga at 5243b89 [master] column_copy: add

Back to archive index

Kouhei Sutou null+****@clear*****
Wed Aug 12 23:47:50 JST 2015


Kouhei Sutou	2015-08-12 23:47:50 +0900 (Wed, 12 Aug 2015)

  New Revision: 5243b8986eadba8cd922278f20f84cc23e772b19
  https://github.com/groonga/groonga/commit/5243b8986eadba8cd922278f20f84cc23e772b19

  Message:
    column_copy: add
    
    It's useful to change table key type and/or column type.
    
    You can change table key type by the following sequence:
    
        table_create old TABLE_HASH_KEY UInt32
        column_create old column1 COLUMN_SCALAR ShortText
        column_create old column2 COLUMN_SCALAR UInt32
    
        table_create new TABLE_HASH_KEY ShortText
        column_create new column1 COLUMN_SCALAR ShortText
        column_create new column2 COLUMN_SCALAR UInt32
    
        column_copy old column1 new column1
        column_copy old column2 new column2
    
        table_remove old
    
    You can change column type by the following sequence:
    
        table_create table TABLE_HASH_KEY UInt32
        column_create table old COLUMN_SCALAR ShortText
    
        column_create table new COLUMN_SCALAR Time
    
        column_copy table old table new
        column_remove table old
        column_rename table new old
    
    TODO:
    
      * Document me
      * Add tests for error cases

  Added files:
    test/command/suite/column_copy/different.expected
    test/command/suite/column_copy/different.test
    test/command/suite/column_copy/same_key_type.expected
    test/command/suite/column_copy/same_key_type.test
    test/command/suite/column_copy/same_table.expected
    test/command/suite/column_copy/same_table.test
  Modified files:
    lib/proc.c

  Modified: lib/proc.c (+294 -0)
===================================================================
--- lib/proc.c    2015-08-12 22:14:07 +0900 (402d36f)
+++ lib/proc.c    2015-08-12 23:47:50 +0900 (c02ef6d)
@@ -6940,6 +6940,294 @@ proc_database_unmap(grn_ctx *ctx, int nargs, grn_obj **args,
   return NULL;
 }
 
+static grn_rc
+proc_column_copy_resolve_target(grn_ctx *ctx,
+                                const char *label,
+                                grn_obj *table_name,
+                                grn_obj *column_name,
+                                grn_obj **table,
+                                grn_obj **column)
+{
+  if (GRN_TEXT_LEN(table_name) == 0) {
+    ERR(GRN_INVALID_ARGUMENT,
+        "[column][copy] %s table name isn't specified",
+        label);
+    return ctx->rc;
+  }
+  *table = grn_ctx_get(ctx,
+                       GRN_TEXT_VALUE(table_name),
+                       GRN_TEXT_LEN(table_name));
+  if (!*table) {
+    ERR(GRN_INVALID_ARGUMENT,
+        "[column][copy] %s table isn't found: <%.*s>",
+        label,
+        (int)GRN_TEXT_LEN(table_name),
+        GRN_TEXT_VALUE(table_name));
+    return ctx->rc;
+  }
+
+  if (GRN_TEXT_LEN(column_name) == 0) {
+    ERR(GRN_INVALID_ARGUMENT,
+        "[column][copy] %s column name isn't specified: <%.*s>",
+        label,
+        (int)GRN_TEXT_LEN(table_name),
+        GRN_TEXT_VALUE(table_name));
+    return ctx->rc;
+  }
+  *column = grn_obj_column(ctx, *table,
+                           GRN_TEXT_VALUE(column_name),
+                           GRN_TEXT_LEN(column_name));
+  if (!*column) {
+    ERR(GRN_INVALID_ARGUMENT,
+        "[column][copy] %s column isn't found: <%.*s.%.*s>",
+        label,
+        (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
+        (int)GRN_TEXT_LEN(column_name), GRN_TEXT_VALUE(column_name));
+    return ctx->rc;
+  }
+
+  return ctx->rc;
+}
+
+static void
+proc_column_copy_same_table(grn_ctx *ctx, grn_obj *table,
+                            grn_obj *from_column, grn_obj *to_column)
+{
+  grn_table_cursor *cursor;
+  grn_id id;
+  grn_obj value;
+
+  cursor = grn_table_cursor_open(ctx, table,
+                                 NULL, 0,
+                                 NULL, 0,
+                                 0, -1, 0);
+  if (!cursor) {
+    return;
+  }
+
+  GRN_VOID_INIT(&value);
+  while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+    GRN_BULK_REWIND(&value);
+    grn_obj_get_value(ctx, from_column, id, &value);
+    grn_obj_set_value(ctx, to_column, id, &value, GRN_OBJ_SET);
+  }
+  GRN_OBJ_FIN(ctx, &value);
+  grn_table_cursor_close(ctx, cursor);
+}
+
+static void
+proc_column_copy_same_key_type(grn_ctx *ctx,
+                               grn_obj *from_table,
+                               grn_obj *from_column,
+                               grn_obj *to_table,
+                               grn_obj *to_column)
+{
+  grn_table_cursor *cursor;
+  grn_id from_id;
+  grn_obj value;
+
+  cursor = grn_table_cursor_open(ctx, from_table,
+                                 NULL, 0,
+                                 NULL, 0,
+                                 0, -1, 0);
+  if (!cursor) {
+    return;
+  }
+
+  GRN_VOID_INIT(&value);
+  while ((from_id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+    void *key;
+    int key_size;
+    grn_id to_id;
+
+    key_size = grn_table_cursor_get_key(ctx, cursor, &key);
+    to_id = grn_table_add(ctx, to_table, key, key_size, NULL);
+    if (to_id == GRN_ID_NIL) {
+      continue;
+    }
+
+    GRN_BULK_REWIND(&value);
+    grn_obj_get_value(ctx, from_column, from_id, &value);
+    grn_obj_set_value(ctx, to_column, to_id, &value, GRN_OBJ_SET);
+  }
+  GRN_OBJ_FIN(ctx, &value);
+  grn_table_cursor_close(ctx, cursor);
+}
+
+static void
+proc_column_copy_different(grn_ctx *ctx,
+                           grn_obj *from_table,
+                           grn_obj *from_column,
+                           grn_obj *to_table,
+                           grn_obj *to_column,
+                           grn_obj *from_table_name,
+                           grn_obj *from_column_name,
+                           grn_obj *to_table_name,
+                           grn_obj *to_column_name)
+{
+  grn_table_cursor *cursor;
+  grn_id from_id;
+  grn_obj from_key_buffer;
+  grn_obj to_key_buffer;
+  grn_obj value;
+
+  cursor = grn_table_cursor_open(ctx, from_table,
+                                 NULL, 0,
+                                 NULL, 0,
+                                 0, -1, 0);
+  if (!cursor) {
+    return;
+  }
+
+  if (from_table->header.domain == GRN_DB_SHORT_TEXT) {
+    GRN_SHORT_TEXT_INIT(&from_key_buffer, 0);
+  } else {
+    GRN_VALUE_FIX_SIZE_INIT(&from_key_buffer, 0, from_table->header.domain);
+  }
+  if (to_table->header.domain == GRN_DB_SHORT_TEXT) {
+    GRN_SHORT_TEXT_INIT(&to_key_buffer, 0);
+  } else {
+    GRN_VALUE_FIX_SIZE_INIT(&to_key_buffer, 0, to_table->header.domain);
+  }
+  GRN_VOID_INIT(&value);
+  while ((from_id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+    void *key;
+    int key_size;
+    grn_rc cast_rc;
+    grn_id to_id;
+
+    GRN_BULK_REWIND(&from_key_buffer);
+    GRN_BULK_REWIND(&to_key_buffer);
+
+    key_size = grn_table_cursor_get_key(ctx, cursor, &key);
+    grn_bulk_write(ctx, &from_key_buffer, key, key_size);
+    cast_rc = grn_obj_cast(ctx, &from_key_buffer, &to_key_buffer, GRN_FALSE);
+    if (cast_rc != GRN_SUCCESS) {
+      grn_obj *to_key_type;
+      grn_obj inspected_key;
+      grn_obj inspected_to_key_type;
+
+      to_key_type = grn_ctx_at(ctx, to_table->header.domain);
+      GRN_TEXT_INIT(&inspected_key, 0);
+      GRN_TEXT_INIT(&inspected_to_key_type, 0);
+      grn_inspect(ctx, &inspected_key, &from_key_buffer);
+      grn_inspect(ctx, &inspected_to_key_type, to_key_type);
+      ERR(cast_rc,
+          "[column][copy] failed to cast key: <%.*s> -> %.*s: "
+          "<%.*s.%.*s> -> <%.*s.%.*s>",
+          (int)GRN_TEXT_LEN(&inspected_key),
+          GRN_TEXT_VALUE(&inspected_key),
+          (int)GRN_TEXT_LEN(&inspected_to_key_type),
+          GRN_TEXT_VALUE(&inspected_to_key_type),
+          (int)GRN_TEXT_LEN(from_table_name),
+          GRN_TEXT_VALUE(from_table_name),
+          (int)GRN_TEXT_LEN(from_column_name),
+          GRN_TEXT_VALUE(from_column_name),
+          (int)GRN_TEXT_LEN(to_table_name),
+          GRN_TEXT_VALUE(to_table_name),
+          (int)GRN_TEXT_LEN(to_column_name),
+          GRN_TEXT_VALUE(to_column_name));
+      GRN_OBJ_FIN(ctx, &inspected_key);
+      GRN_OBJ_FIN(ctx, &inspected_to_key_type);
+      break;
+    }
+    to_id = grn_table_add(ctx, to_table,
+                          GRN_BULK_HEAD(&to_key_buffer),
+                          GRN_BULK_VSIZE(&to_key_buffer),
+                          NULL);
+    if (to_id == GRN_ID_NIL) {
+      continue;
+    }
+
+    GRN_BULK_REWIND(&value);
+    grn_obj_get_value(ctx, from_column, from_id, &value);
+    grn_obj_set_value(ctx, to_column, to_id, &value, GRN_OBJ_SET);
+  }
+  GRN_OBJ_FIN(ctx, &from_key_buffer);
+  GRN_OBJ_FIN(ctx, &to_key_buffer);
+  GRN_OBJ_FIN(ctx, &value);
+
+  grn_table_cursor_close(ctx, cursor);
+}
+
+static grn_obj *
+proc_column_copy(grn_ctx *ctx, int nargs, grn_obj **args,
+                 grn_user_data *user_data)
+{
+  grn_rc rc = GRN_SUCCESS;
+  grn_obj *from_table = NULL;
+  grn_obj *from_column = NULL;
+  grn_obj *to_table = NULL;
+  grn_obj *to_column = NULL;
+  grn_obj *from_table_name = VAR(0);
+  grn_obj *from_column_name = VAR(1);
+  grn_obj *to_table_name = VAR(2);
+  grn_obj *to_column_name = VAR(3);
+
+  rc = proc_column_copy_resolve_target(ctx, "from",
+                                       from_table_name, from_column_name,
+                                       &from_table, &from_column);
+  if (rc != GRN_SUCCESS) {
+    goto exit;
+  }
+  rc = proc_column_copy_resolve_target(ctx, "to",
+                                       to_table_name, to_column_name,
+                                       &to_table, &to_column);
+  if (rc != GRN_SUCCESS) {
+    goto exit;
+  }
+
+  if ((from_table->header.type == GRN_TABLE_NO_KEY ||
+       to_table->header.type == GRN_TABLE_NO_KEY) &&
+      from_table != to_table) {
+    rc = GRN_OPERATION_NOT_SUPPORTED;
+    ERR(rc,
+        "[column][copy] copy from/to TABLE_NO_KEY isn't supported: "
+        "<%.*s.%.*s> -> <%.*s.%.*s>",
+        (int)GRN_TEXT_LEN(from_table_name), GRN_TEXT_VALUE(from_table_name),
+        (int)GRN_TEXT_LEN(from_column_name), GRN_TEXT_VALUE(from_column_name),
+        (int)GRN_TEXT_LEN(to_table_name), GRN_TEXT_VALUE(to_table_name),
+        (int)GRN_TEXT_LEN(to_column_name), GRN_TEXT_VALUE(to_column_name));
+    goto exit;
+  }
+
+  if (from_table == to_table) {
+    proc_column_copy_same_table(ctx, from_table, from_column, to_column);
+  } else if (from_table->header.domain == to_table->header.domain) {
+    proc_column_copy_same_key_type(ctx,
+                                   from_table, from_column,
+                                   to_table, to_column);
+  } else {
+    proc_column_copy_different(ctx,
+                               from_table,
+                               from_column,
+                               to_table,
+                               to_column,
+                               from_table_name,
+                               from_column_name,
+                               to_table_name,
+                               to_column_name);
+  }
+
+exit :
+  GRN_OUTPUT_BOOL(!rc);
+
+  if (to_column) {
+    grn_obj_unlink(ctx, to_column);
+  }
+  if (to_table) {
+    grn_obj_unlink(ctx, to_table);
+  }
+  if (from_column) {
+    grn_obj_unlink(ctx, from_column);
+  }
+  if (from_table) {
+    grn_obj_unlink(ctx, from_table);
+  }
+
+  return NULL;
+}
+
 #define DEF_VAR(v,name_str) do {\
   (v).name = (name_str);\
   (v).name_size = GRN_STRLEN(name_str);\
@@ -7231,4 +7519,10 @@ grn_db_init_builtin_query(grn_ctx *ctx)
   DEF_COMMAND("thread_count", proc_thread_count, 1, vars);
 
   DEF_COMMAND("database_unmap", proc_database_unmap, 0, vars);
+
+  DEF_VAR(vars[0], "from_table");
+  DEF_VAR(vars[1], "from_name");
+  DEF_VAR(vars[2], "to_table");
+  DEF_VAR(vars[3], "to_name");
+  DEF_COMMAND("column_copy", proc_column_copy, 4, vars);
 }

  Added: test/command/suite/column_copy/different.expected (+33 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/column_copy/different.expected    2015-08-12 23:47:50 +0900 (cd90151)
@@ -0,0 +1,33 @@
+table_create SmallNumbers TABLE_HASH_KEY UInt8
+[[0,0.0,0.0],true]
+column_create SmallNumbers id_uint8 COLUMN_SCALAR UInt8
+[[0,0.0,0.0],true]
+load --table SmallNumbers
+[
+{"_key": 10, "id_uint8": 11},
+{"_key": 20, "id_uint8": 22},
+{"_key": 30, "id_uint8": 33}
+]
+[[0,0.0,0.0],3]
+table_create LargeNumbers TABLE_HASH_KEY UInt64
+[[0,0.0,0.0],true]
+column_create LargeNumbers id_text COLUMN_SCALAR Text
+[[0,0.0,0.0],true]
+column_copy SmallNumbers id_uint8 LargeNumbers id_text
+[[0,0.0,0.0],true]
+dump --dump_schema no
+load --table SmallNumbers
+[
+["_key","id_uint8"],
+[10,11],
+[20,22],
+[30,33]
+]
+
+load --table LargeNumbers
+[
+["_key","id_text"],
+[10,"11"],
+[20,"22"],
+[30,"33"]
+]

  Added: test/command/suite/column_copy/different.test (+16 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/column_copy/different.test    2015-08-12 23:47:50 +0900 (84a9667)
@@ -0,0 +1,16 @@
+table_create SmallNumbers TABLE_HASH_KEY UInt8
+column_create SmallNumbers id_uint8 COLUMN_SCALAR UInt8
+
+load --table SmallNumbers
+[
+{"_key": 10, "id_uint8": 11},
+{"_key": 20, "id_uint8": 22},
+{"_key": 30, "id_uint8": 33}
+]
+
+table_create LargeNumbers TABLE_HASH_KEY UInt64
+column_create LargeNumbers id_text COLUMN_SCALAR Text
+
+column_copy SmallNumbers id_uint8 LargeNumbers id_text
+
+dump --dump_schema no

  Added: test/command/suite/column_copy/same_key_type.expected (+33 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/column_copy/same_key_type.expected    2015-08-12 23:47:50 +0900 (f9a52f7)
@@ -0,0 +1,33 @@
+table_create Users TABLE_HASH_KEY ShortText
+[[0,0.0,0.0],true]
+column_create Users age_text COLUMN_SCALAR Text
+[[0,0.0,0.0],true]
+load --table Users
+[
+{"_key": "alice",   "age_text": "12"},
+{"_key": "bob",     "age_text": "29"},
+{"_key": "charlie", "age_text": "9"}
+]
+[[0,0.0,0.0],3]
+table_create Friends TABLE_PAT_KEY ShortText
+[[0,0.0,0.0],true]
+column_create Friends age_uint8 COLUMN_SCALAR UInt8
+[[0,0.0,0.0],true]
+column_copy Users age_text Friends age_uint8
+[[0,0.0,0.0],true]
+dump --dump_schema no
+load --table Users
+[
+["_key","age_text"],
+["alice","12"],
+["bob","29"],
+["charlie","9"]
+]
+
+load --table Friends
+[
+["_key","age_uint8"],
+["alice",12],
+["bob",29],
+["charlie",9]
+]

  Added: test/command/suite/column_copy/same_key_type.test (+15 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/column_copy/same_key_type.test    2015-08-12 23:47:50 +0900 (db8ab03)
@@ -0,0 +1,15 @@
+table_create Users TABLE_HASH_KEY ShortText
+column_create Users age_text COLUMN_SCALAR Text
+
+load --table Users
+[
+{"_key": "alice",   "age_text": "12"},
+{"_key": "bob",     "age_text": "29"},
+{"_key": "charlie", "age_text": "9"}
+]
+
+table_create Friends TABLE_PAT_KEY ShortText
+column_create Friends age_uint8 COLUMN_SCALAR UInt8
+column_copy Users age_text Friends age_uint8
+
+dump --dump_schema no

  Added: test/command/suite/column_copy/same_table.expected (+23 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/column_copy/same_table.expected    2015-08-12 23:47:50 +0900 (78a6093)
@@ -0,0 +1,23 @@
+table_create Logs TABLE_NO_KEY
+[[0,0.0,0.0],true]
+column_create Logs timestamp_text COLUMN_SCALAR Text
+[[0,0.0,0.0],true]
+load --table Logs
+[
+{"timestamp_text": "2015-08-12 00:00:00"},
+{"timestamp_text": "2015-08-12 00:00:01"},
+{"timestamp_text": "2015-08-12 00:00:02"}
+]
+[[0,0.0,0.0],3]
+column_create Logs timestamp_time COLUMN_SCALAR Time
+[[0,0.0,0.0],true]
+column_copy Logs timestamp_text Logs timestamp_time
+[[0,0.0,0.0],true]
+dump --dump_schema no
+load --table Logs
+[
+["_id","timestamp_text","timestamp_time"],
+[1,"2015-08-12 00:00:00",1439305200.0],
+[2,"2015-08-12 00:00:01",1439305201.0],
+[3,"2015-08-12 00:00:02",1439305202.0]
+]

  Added: test/command/suite/column_copy/same_table.test (+14 -0) 100644
===================================================================
--- /dev/null
+++ test/command/suite/column_copy/same_table.test    2015-08-12 23:47:50 +0900 (a137b08)
@@ -0,0 +1,14 @@
+table_create Logs TABLE_NO_KEY
+column_create Logs timestamp_text COLUMN_SCALAR Text
+
+load --table Logs
+[
+{"timestamp_text": "2015-08-12 00:00:00"},
+{"timestamp_text": "2015-08-12 00:00:01"},
+{"timestamp_text": "2015-08-12 00:00:02"}
+]
+
+column_create Logs timestamp_time COLUMN_SCALAR Time
+column_copy Logs timestamp_text Logs timestamp_time
+
+dump --dump_schema no
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index