1 /* -*- c-basic-offset: 2 -*- */
2 /*
3   Copyright(C) 2009-2017 Brazil
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License version 2.1 as published by the Free Software Foundation.
8 
9   This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13 
14   You should have received a copy of the GNU Lesser General Public
15   License along with this library; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
17 */
18 
19 #include "grn_load.h"
20 #include "grn_ctx_impl.h"
21 #include "grn_db.h"
22 #include "grn_util.h"
23 
24 static void
grn_loader_save_error(grn_ctx * ctx,grn_loader * loader)25 grn_loader_save_error(grn_ctx *ctx, grn_loader *loader)
26 {
27   loader->rc = ctx->rc;
28   grn_strcpy(loader->errbuf, GRN_CTX_MSGSIZE, ctx->errbuf);
29 }
30 
31 static grn_obj *
values_add(grn_ctx * ctx,grn_loader * loader)32 values_add(grn_ctx *ctx, grn_loader *loader)
33 {
34   grn_obj *res;
35   uint32_t curr_size = loader->values_size * sizeof(grn_obj);
36   if (curr_size < GRN_TEXT_LEN(&loader->values)) {
37     res = (grn_obj *)(GRN_TEXT_VALUE(&loader->values) + curr_size);
38     res->header.domain = GRN_DB_TEXT;
39     GRN_BULK_REWIND(res);
40   } else {
41     if (grn_bulk_space(ctx, &loader->values, sizeof(grn_obj))) { return NULL; }
42     res = (grn_obj *)(GRN_TEXT_VALUE(&loader->values) + curr_size);
43     GRN_TEXT_INIT(res, 0);
44   }
45   loader->values_size++;
46   loader->last = res;
47   return res;
48 }
49 
50 static grn_obj *
values_next(grn_ctx * ctx,grn_obj * value)51 values_next(grn_ctx *ctx, grn_obj *value)
52 {
53   if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET ||
54       value->header.domain == GRN_JSON_LOAD_OPEN_BRACE) {
55     value += GRN_UINT32_VALUE(value);
56   }
57   return value + 1;
58 }
59 
60 static int
values_len(grn_ctx * ctx,grn_obj * head,grn_obj * tail)61 values_len(grn_ctx *ctx, grn_obj *head, grn_obj *tail)
62 {
63   int len;
64   for (len = 0; head < tail; head = values_next(ctx, head), len++) ;
65   return len;
66 }
67 
68 static grn_id
loader_add(grn_ctx * ctx,grn_obj * key)69 loader_add(grn_ctx *ctx, grn_obj *key)
70 {
71   int added = 0;
72   grn_loader *loader = &ctx->impl->loader;
73   grn_id id = grn_table_add_by_key(ctx, loader->table, key, &added);
74   if (id == GRN_ID_NIL) {
75     grn_loader_save_error(ctx, loader);
76     return id;
77   }
78   if (!added && loader->ifexists) {
79     grn_obj *v = grn_expr_get_var_by_offset(ctx, loader->ifexists, 0);
80     grn_obj *result;
81     GRN_RECORD_SET(ctx, v, id);
82     result = grn_expr_exec(ctx, loader->ifexists, 0);
83     if (!grn_obj_is_true(ctx, result)) {
84       id = 0;
85     }
86   }
87   return id;
88 }
89 
90 static void
add_weight_vector(grn_ctx * ctx,grn_obj * column,grn_obj * value,grn_obj * vector)91 add_weight_vector(grn_ctx *ctx,
92                   grn_obj *column,
93                   grn_obj *value,
94                   grn_obj *vector)
95 {
96   unsigned int i, n;
97   grn_obj weight_buffer;
98 
99   n = GRN_UINT32_VALUE(value);
100   GRN_UINT32_INIT(&weight_buffer, 0);
101   for (i = 0; i < n; i += 2) {
102     grn_rc rc;
103     grn_obj *key, *weight;
104 
105     key = value + 1 + i;
106     weight = key + 1;
107 
108     GRN_BULK_REWIND(&weight_buffer);
109     rc = grn_obj_cast(ctx, weight, &weight_buffer, GRN_TRUE);
110     if (rc != GRN_SUCCESS) {
111       grn_obj *range;
112       range = grn_ctx_at(ctx, weight_buffer.header.domain);
113       ERR_CAST(column, range, weight);
114       grn_obj_unlink(ctx, range);
115       break;
116     }
117     grn_vector_add_element(ctx,
118                            vector,
119                            GRN_BULK_HEAD(key),
120                            GRN_BULK_VSIZE(key),
121                            GRN_UINT32_VALUE(&weight_buffer),
122                            key->header.domain);
123   }
124   GRN_OBJ_FIN(ctx, &weight_buffer);
125 }
126 
127 static void
set_vector(grn_ctx * ctx,grn_obj * column,grn_id id,grn_obj * vector)128 set_vector(grn_ctx *ctx, grn_obj *column, grn_id id, grn_obj *vector)
129 {
130   int n = GRN_UINT32_VALUE(vector);
131   grn_obj buf, *v = vector + 1;
132   grn_id range_id;
133   grn_obj *range;
134 
135   range_id = DB_OBJ(column)->range;
136   range = grn_ctx_at(ctx, range_id);
137   if (grn_obj_is_table(ctx, range)) {
138     GRN_RECORD_INIT(&buf, GRN_OBJ_VECTOR, range_id);
139     while (n--) {
140       grn_bool cast_failed = GRN_FALSE;
141       grn_obj record, *element = v;
142       if (range_id != element->header.domain) {
143         GRN_RECORD_INIT(&record, 0, range_id);
144         if (grn_obj_cast(ctx, element, &record, GRN_TRUE)) {
145           cast_failed = GRN_TRUE;
146           ERR_CAST(column, range, element);
147         }
148         element = &record;
149       }
150       if (!cast_failed) {
151         GRN_UINT32_PUT(ctx, &buf, GRN_RECORD_VALUE(element));
152       }
153       if (element == &record) { GRN_OBJ_FIN(ctx, element); }
154       v = values_next(ctx, v);
155     }
156   } else {
157     if (((struct _grn_type *)range)->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
158       GRN_TEXT_INIT(&buf, GRN_OBJ_VECTOR);
159       while (n--) {
160         switch (v->header.domain) {
161         case GRN_DB_TEXT :
162         {
163           grn_bool cast_failed = GRN_FALSE;
164           grn_obj casted_element, *element = v;
165           if (range_id != element->header.domain) {
166             GRN_OBJ_INIT(&casted_element, GRN_BULK, 0, range_id);
167             if (grn_obj_cast(ctx, element, &casted_element, GRN_TRUE)) {
168               cast_failed = GRN_TRUE;
169               ERR_CAST(column, range, element);
170             }
171             element = &casted_element;
172           }
173           if (!cast_failed) {
174             grn_vector_add_element(ctx, &buf,
175                                    GRN_TEXT_VALUE(element),
176                                    GRN_TEXT_LEN(element),
177                                    0,
178                                    element->header.domain);
179           }
180           if (element == &casted_element) { GRN_OBJ_FIN(ctx, element); }
181           break;
182         }
183         case GRN_JSON_LOAD_OPEN_BRACE :
184           add_weight_vector(ctx, column, v, &buf);
185           n -= GRN_UINT32_VALUE(v);
186           break;
187         default :
188           ERR(GRN_INVALID_ARGUMENT, "array must contain string or object");
189           break;
190         }
191         v = values_next(ctx, v);
192       }
193     } else {
194       grn_id value_size = ((grn_db_obj *)range)->range;
195       GRN_VALUE_FIX_SIZE_INIT(&buf, GRN_OBJ_VECTOR, range_id);
196       while (n--) {
197         grn_bool cast_failed = GRN_FALSE;
198         grn_obj casted_element, *element = v;
199         if (range_id != element->header.domain) {
200           GRN_OBJ_INIT(&casted_element, GRN_BULK, 0, range_id);
201           if (grn_obj_cast(ctx, element, &casted_element, GRN_TRUE)) {
202             cast_failed = GRN_TRUE;
203             ERR_CAST(column, range, element);
204           }
205           element = &casted_element;
206         }
207         if (!cast_failed) {
208           grn_bulk_write(ctx, &buf, GRN_TEXT_VALUE(element), value_size);
209         }
210         if (element == &casted_element) { GRN_OBJ_FIN(ctx, element); }
211         v = values_next(ctx, v);
212       }
213     }
214   }
215   grn_obj_set_value(ctx, column, id, &buf, GRN_OBJ_SET);
216   GRN_OBJ_FIN(ctx, &buf);
217 }
218 
219 static void
set_weight_vector(grn_ctx * ctx,grn_obj * column,grn_id id,grn_obj * value)220 set_weight_vector(grn_ctx *ctx, grn_obj *column, grn_id id, grn_obj *value)
221 {
222   if (!grn_obj_is_weight_vector_column(ctx, column)) {
223     char column_name[GRN_TABLE_MAX_KEY_SIZE];
224     int column_name_size;
225     column_name_size = grn_obj_name(ctx, column, column_name,
226                                     GRN_TABLE_MAX_KEY_SIZE);
227     ERR(GRN_INVALID_ARGUMENT,
228         "<%.*s>: columns except weight vector column don't support object value",
229         column_name_size, column_name);
230     return;
231   }
232 
233   {
234     grn_obj vector;
235 
236     GRN_TEXT_INIT(&vector, GRN_OBJ_VECTOR);
237     add_weight_vector(ctx, column, value, &vector);
238     grn_obj_set_value(ctx, column, id, &vector, GRN_OBJ_SET);
239     GRN_OBJ_FIN(ctx, &vector);
240   }
241 }
242 
243 static inline int
name_equal(const char * p,unsigned int size,const char * name)244 name_equal(const char *p, unsigned int size, const char *name)
245 {
246   if (strlen(name) != size) { return 0; }
247   if (*p != GRN_DB_PSEUDO_COLUMN_PREFIX) { return 0; }
248   return !memcmp(p + 1, name + 1, size - 1);
249 }
250 
251 static void
report_set_column_value_failure(grn_ctx * ctx,grn_obj * key,const char * column_name,unsigned int column_name_size,grn_obj * column_value)252 report_set_column_value_failure(grn_ctx *ctx,
253                                 grn_obj *key,
254                                 const char *column_name,
255                                 unsigned int column_name_size,
256                                 grn_obj *column_value)
257 {
258   grn_obj key_inspected, column_value_inspected;
259 
260   GRN_TEXT_INIT(&key_inspected, 0);
261   GRN_TEXT_INIT(&column_value_inspected, 0);
262   grn_inspect_limited(ctx, &key_inspected, key);
263   grn_inspect_limited(ctx, &column_value_inspected, column_value);
264   GRN_LOG(ctx, GRN_LOG_ERROR,
265           "[table][load] failed to set column value: %s: "
266           "key: <%.*s>, column: <%.*s>, value: <%.*s>",
267           ctx->errbuf,
268           (int)GRN_TEXT_LEN(&key_inspected),
269           GRN_TEXT_VALUE(&key_inspected),
270           column_name_size,
271           column_name,
272           (int)GRN_TEXT_LEN(&column_value_inspected),
273           GRN_TEXT_VALUE(&column_value_inspected));
274   GRN_OBJ_FIN(ctx, &key_inspected);
275   GRN_OBJ_FIN(ctx, &column_value_inspected);
276 }
277 
278 static grn_id
parse_id_value(grn_ctx * ctx,grn_obj * value)279 parse_id_value(grn_ctx *ctx, grn_obj *value)
280 {
281   switch (value->header.type) {
282   case GRN_DB_UINT32 :
283     return GRN_UINT32_VALUE(value);
284   case GRN_DB_INT32 :
285     return GRN_INT32_VALUE(value);
286   default :
287     {
288       grn_id id = GRN_ID_NIL;
289       grn_obj casted_value;
290       GRN_UINT32_INIT(&casted_value, 0);
291       if (grn_obj_cast(ctx, value, &casted_value, GRN_FALSE) != GRN_SUCCESS) {
292         grn_obj inspected;
293         GRN_TEXT_INIT(&inspected, 0);
294         grn_inspect(ctx, &inspected, value);
295         ERR(GRN_INVALID_ARGUMENT,
296             "<%s>: failed to cast to <UInt32>: <%.*s>",
297             GRN_COLUMN_NAME_ID,
298             (int)GRN_TEXT_LEN(&inspected),
299             GRN_TEXT_VALUE(&inspected));
300         GRN_OBJ_FIN(ctx, &inspected);
301       } else {
302         id = GRN_UINT32_VALUE(&casted_value);
303       }
304       GRN_OBJ_FIN(ctx, &casted_value);
305       return id;
306     }
307   }
308 }
309 
310 static void
bracket_close(grn_ctx * ctx,grn_loader * loader)311 bracket_close(grn_ctx *ctx, grn_loader *loader)
312 {
313   grn_id id = GRN_ID_NIL;
314   grn_obj *value, *value_end, *id_value = NULL, *key_value = NULL;
315   grn_obj *col, **cols; /* Columns except _id and _key. */
316   uint32_t i, begin;
317   uint32_t ncols;   /* Number of columns except _id and _key. */
318   uint32_t nvalues; /* Number of values in brackets. */
319   uint32_t depth;
320   grn_bool is_record_load = GRN_FALSE;
321 
322   cols = (grn_obj **)GRN_BULK_HEAD(&loader->columns);
323   ncols = GRN_BULK_VSIZE(&loader->columns) / sizeof(grn_obj *);
324   GRN_UINT32_POP(&loader->level, begin);
325   value = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + begin;
326   value_end = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + loader->values_size;
327   GRN_ASSERT(value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET);
328   GRN_UINT32_SET(ctx, value, loader->values_size - begin - 1);
329   value++;
330   depth = GRN_BULK_VSIZE(&loader->level);
331   if (depth > sizeof(uint32_t) * loader->emit_level) {
332     return;
333   }
334   if (depth == 0 || !loader->table ||
335       loader->columns_status == GRN_LOADER_COLUMNS_BROKEN) {
336     goto exit;
337   }
338   nvalues = values_len(ctx, value, value_end);
339 
340   if (loader->columns_status == GRN_LOADER_COLUMNS_UNSET) {
341     /*
342      * Target columns and _id or _key are not specified yet and values are
343      * handled as column names and "_id" or "_key".
344      */
345     for (i = 0; i < nvalues; i++) {
346       const char *col_name;
347       unsigned int col_name_size;
348       if (value->header.domain != GRN_DB_TEXT) {
349         grn_obj buffer;
350         GRN_TEXT_INIT(&buffer, 0);
351         grn_inspect(ctx, &buffer, value);
352         ERR(GRN_INVALID_ARGUMENT,
353             "column name must be string: <%.*s>",
354             (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
355         grn_loader_save_error(ctx, loader);
356         GRN_OBJ_FIN(ctx, &buffer);
357         loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
358         goto exit;
359       }
360       col_name = GRN_TEXT_VALUE(value);
361       col_name_size = GRN_TEXT_LEN(value);
362       col = grn_obj_column(ctx, loader->table, col_name, col_name_size);
363       if (!col) {
364         ERR(GRN_INVALID_ARGUMENT, "nonexistent column: <%.*s>",
365             col_name_size, col_name);
366         grn_loader_save_error(ctx, loader);
367         loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
368         goto exit;
369       }
370       if (name_equal(col_name, col_name_size, GRN_COLUMN_NAME_ID)) {
371         grn_obj_unlink(ctx, col);
372         if (loader->id_offset != -1 || loader->key_offset != -1) {
373           /* _id and _key must not appear more than once. */
374           if (loader->id_offset != -1) {
375             ERR(GRN_INVALID_ARGUMENT,
376                 "duplicated id and key columns: <%s> at %d and <%s> at %d",
377                 GRN_COLUMN_NAME_ID, i,
378                 GRN_COLUMN_NAME_ID, loader->id_offset);
379           } else {
380             ERR(GRN_INVALID_ARGUMENT,
381                 "duplicated id and key columns: <%s> at %d and <%s> at %d",
382                 GRN_COLUMN_NAME_ID, i,
383                 GRN_COLUMN_NAME_KEY, loader->key_offset);
384           }
385           grn_loader_save_error(ctx, loader);
386           loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
387           goto exit;
388         }
389         loader->id_offset = i;
390       } else if (name_equal(col_name, col_name_size, GRN_COLUMN_NAME_KEY)) {
391         grn_obj_unlink(ctx, col);
392         if (loader->id_offset != -1 || loader->key_offset != -1) {
393           /* _id and _key must not appear more than once. */
394           if (loader->id_offset != -1) {
395             ERR(GRN_INVALID_ARGUMENT,
396                 "duplicated id and key columns: <%s> at %d and <%s> at %d",
397                 GRN_COLUMN_NAME_KEY, i,
398                 GRN_COLUMN_NAME_ID, loader->id_offset);
399           } else {
400             ERR(GRN_INVALID_ARGUMENT,
401                 "duplicated id and key columns: <%s> at %d and <%s> at %d",
402                 GRN_COLUMN_NAME_KEY, i,
403                 GRN_COLUMN_NAME_KEY, loader->key_offset);
404           }
405           grn_loader_save_error(ctx, loader);
406           loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
407           goto exit;
408         }
409         loader->key_offset = i;
410       } else {
411         GRN_PTR_PUT(ctx, &loader->columns, col);
412       }
413       value++;
414     }
415     switch (loader->table->header.type) {
416     case GRN_TABLE_HASH_KEY :
417     case GRN_TABLE_PAT_KEY :
418     case GRN_TABLE_DAT_KEY :
419       if (loader->id_offset == -1 && loader->key_offset == -1) {
420         ERR(GRN_INVALID_ARGUMENT, "missing id or key column");
421         grn_loader_save_error(ctx, loader);
422         loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
423         goto exit;
424       }
425       break;
426     }
427     loader->columns_status = GRN_LOADER_COLUMNS_SET;
428     goto exit;
429   }
430 
431   is_record_load = GRN_TRUE;
432 
433   /* Target columns and _id or _key are already specified. */
434   if (!nvalues) {
435     /*
436      * Accept empty arrays because a dump command may output a load command
437      * which contains empty arrays for a table with deleted records.
438      */
439     id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
440   } else {
441     uint32_t expected_nvalues = ncols;
442     if (loader->id_offset != -1 || loader->key_offset != -1) {
443       expected_nvalues++;
444     }
445     if (nvalues != expected_nvalues) {
446       ERR(GRN_INVALID_ARGUMENT,
447           "unexpected #values: expected:%u, actual:%u",
448           expected_nvalues, nvalues);
449       grn_loader_save_error(ctx, loader);
450       goto exit;
451     }
452     if (loader->id_offset != -1) {
453       id_value = value + loader->id_offset;
454       id = parse_id_value(ctx, id_value);
455       if (grn_table_at(ctx, loader->table, id) == GRN_ID_NIL) {
456         id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
457       }
458     } else if (loader->key_offset != -1) {
459       key_value = value + loader->key_offset;
460       id = loader_add(ctx, key_value);
461     } else {
462       id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
463     }
464   }
465   if (id == GRN_ID_NIL) {
466     /* Target record is not available. */
467     goto exit;
468   }
469 
470   for (i = 0; i < nvalues; i++, value = values_next(ctx, value)) {
471     if (i == loader->id_offset || i == loader->key_offset) {
472        /* Skip _id and _key, because it's already used to get id. */
473        continue;
474     }
475     col = *cols;
476     if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
477       set_vector(ctx, col, id, value);
478     } else if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACE) {
479       set_weight_vector(ctx, col, id, value);
480     } else {
481       grn_obj_set_value(ctx, col, id, value, GRN_OBJ_SET);
482     }
483     if (ctx->rc != GRN_SUCCESS) {
484       char column_name[GRN_TABLE_MAX_KEY_SIZE];
485       unsigned int column_name_size;
486       grn_loader_save_error(ctx, loader);
487       column_name_size = grn_obj_name(ctx, col, column_name,
488                                       GRN_TABLE_MAX_KEY_SIZE);
489       report_set_column_value_failure(ctx, key_value,
490                                       column_name, column_name_size,
491                                       value);
492       ERRCLR(ctx);
493     }
494     cols++;
495   }
496   if (loader->each) {
497     grn_obj *v = grn_expr_get_var_by_offset(ctx, loader->each, 0);
498     GRN_RECORD_SET(ctx, v, id);
499     grn_expr_exec(ctx, loader->each, 0);
500   }
501   loader->nrecords++;
502 exit:
503   if (is_record_load) {
504     if (loader->output_ids) {
505       GRN_UINT32_PUT(ctx, &(loader->ids), id);
506     }
507     if (loader->output_errors) {
508       GRN_INT32_PUT(ctx, &(loader->return_codes), ctx->rc);
509       grn_vector_add_element(ctx,
510                              &(loader->error_messages),
511                              ctx->errbuf,
512                              strlen(ctx->errbuf),
513                              0,
514                              GRN_DB_TEXT);
515     }
516   }
517   loader->values_size = begin;
518   ERRCLR(ctx);
519 }
520 
521 static void
brace_close(grn_ctx * ctx,grn_loader * loader)522 brace_close(grn_ctx *ctx, grn_loader *loader)
523 {
524   grn_id id = GRN_ID_NIL;
525   grn_obj *value, *value_begin, *value_end;
526   grn_obj *id_value = NULL, *key_value = NULL;
527   uint32_t begin;
528 
529   GRN_UINT32_POP(&loader->level, begin);
530   value_begin = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + begin;
531   value_end = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + loader->values_size;
532   GRN_ASSERT(value->header.domain == GRN_JSON_LOAD_OPEN_BRACE);
533   GRN_UINT32_SET(ctx, value_begin, loader->values_size - begin - 1);
534   value_begin++;
535   if (GRN_BULK_VSIZE(&loader->level) > sizeof(uint32_t) * loader->emit_level) {
536     return;
537   }
538   if (!loader->table) {
539     goto exit;
540   }
541 
542   /* Scan values to find _id or _key. */
543   for (value = value_begin; value + 1 < value_end;
544        value = values_next(ctx, value)) {
545     const char *name = GRN_TEXT_VALUE(value);
546     unsigned int name_size = GRN_TEXT_LEN(value);
547     if (value->header.domain != GRN_DB_TEXT) {
548       grn_obj buffer;
549       GRN_TEXT_INIT(&buffer, 0);
550       grn_inspect(ctx, &buffer, value);
551       GRN_LOG(ctx, GRN_LOG_ERROR,
552               "column name must be string: <%.*s>",
553               (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
554       GRN_OBJ_FIN(ctx, &buffer);
555       goto exit;
556     }
557     value++;
558     if (name_equal(name, name_size, GRN_COLUMN_NAME_ID)) {
559       if (id_value || key_value) {
560         if (loader->table->header.type == GRN_TABLE_NO_KEY) {
561           GRN_LOG(ctx, GRN_LOG_ERROR, "duplicated '_id' column");
562           goto exit;
563         } else {
564           GRN_LOG(ctx, GRN_LOG_ERROR,
565                   "duplicated key columns: %s and %s",
566                   id_value ? GRN_COLUMN_NAME_ID : GRN_COLUMN_NAME_KEY,
567                   GRN_COLUMN_NAME_ID);
568           goto exit;
569         }
570       }
571       id_value = value;
572     } else if (name_equal(name, name_size, GRN_COLUMN_NAME_KEY)) {
573       if (id_value || key_value) {
574         GRN_LOG(ctx, GRN_LOG_ERROR,
575                 "duplicated key columns: %s and %s",
576                 id_value ? GRN_COLUMN_NAME_ID : GRN_COLUMN_NAME_KEY,
577                 GRN_COLUMN_NAME_KEY);
578         goto exit;
579       }
580       key_value = value;
581     }
582   }
583 
584   switch (loader->table->header.type) {
585   case GRN_TABLE_HASH_KEY :
586   case GRN_TABLE_PAT_KEY :
587   case GRN_TABLE_DAT_KEY :
588     /* The target table requires _id or _key. */
589     if (!id_value && !key_value) {
590       GRN_LOG(ctx, GRN_LOG_ERROR, "neither _key nor _id is assigned");
591       goto exit;
592     }
593     break;
594   default :
595     /* The target table does not have _key. */
596     if (key_value) {
597       GRN_LOG(ctx, GRN_LOG_ERROR, "nonexistent key value");
598       goto exit;
599     }
600     break;
601   }
602 
603   if (id_value) {
604     id = parse_id_value(ctx, id_value);
605     if (grn_table_at(ctx, loader->table, id) == GRN_ID_NIL) {
606       if (ctx->rc == GRN_SUCCESS) {
607         id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
608       }
609     }
610   } else if (key_value) {
611     id = loader_add(ctx, key_value);
612   } else {
613     id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
614   }
615   if (id == GRN_ID_NIL) {
616     /* Target record is not available. */
617     goto exit;
618   }
619 
620   for (value = value_begin; value + 1 < value_end;
621        value = values_next(ctx, value)) {
622     grn_obj *col;
623     const char *name = GRN_TEXT_VALUE(value);
624     unsigned int name_size = GRN_TEXT_LEN(value);
625     value++;
626     if (value == id_value || value == key_value) {
627       /* Skip _id and _key, because it's already used to get id. */
628       continue;
629     }
630     col = grn_obj_column(ctx, loader->table, name, name_size);
631     if (!col) {
632       GRN_LOG(ctx, GRN_LOG_ERROR, "invalid column('%.*s')",
633               (int)name_size, name);
634       /* Automatic column creation is disabled. */
635       /*
636       if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
637         grn_obj *v = value + 1;
638         col = grn_column_create(ctx, loader->table, name, name_size,
639                                 NULL, GRN_OBJ_PERSISTENT|GRN_OBJ_COLUMN_VECTOR,
640                                 grn_ctx_at(ctx, v->header.domain));
641       } else {
642         col = grn_column_create(ctx, loader->table, name, name_size,
643                                 NULL, GRN_OBJ_PERSISTENT,
644                                 grn_ctx_at(ctx, value->header.domain));
645       }
646       */
647     } else {
648       if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
649         set_vector(ctx, col, id, value);
650       } else if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACE) {
651         set_weight_vector(ctx, col, id, value);
652       } else {
653         grn_obj_set_value(ctx, col, id, value, GRN_OBJ_SET);
654       }
655       if (ctx->rc != GRN_SUCCESS) {
656         grn_loader_save_error(ctx, loader);
657         report_set_column_value_failure(ctx, key_value,
658                                         name, name_size, value);
659         ERRCLR(ctx);
660       }
661       grn_obj_unlink(ctx, col);
662     }
663   }
664   if (loader->each) {
665     value = grn_expr_get_var_by_offset(ctx, loader->each, 0);
666     GRN_RECORD_SET(ctx, value, id);
667     grn_expr_exec(ctx, loader->each, 0);
668   }
669   loader->nrecords++;
670 exit:
671   if (loader->output_ids) {
672     GRN_UINT32_PUT(ctx, &(loader->ids), id);
673   }
674   if (loader->output_errors) {
675     GRN_INT32_PUT(ctx, &(loader->return_codes), ctx->rc);
676     grn_vector_add_element(ctx,
677                            &(loader->error_messages),
678                            ctx->errbuf,
679                            strlen(ctx->errbuf),
680                            0,
681                            GRN_DB_TEXT);
682   }
683   loader->values_size = begin;
684   ERRCLR(ctx);
685 }
686 
687 #define JSON_READ_OPEN_BRACKET() do {\
688   GRN_UINT32_PUT(ctx, &loader->level, loader->values_size);\
689   values_add(ctx, loader);\
690   loader->last->header.domain = GRN_JSON_LOAD_OPEN_BRACKET;\
691   loader->stat = GRN_LOADER_TOKEN;\
692   str++;\
693 } while (0)
694 
695 #define JSON_READ_OPEN_BRACE() do {\
696   GRN_UINT32_PUT(ctx, &loader->level, loader->values_size);\
697   values_add(ctx, loader);\
698   loader->last->header.domain = GRN_JSON_LOAD_OPEN_BRACE;\
699   loader->stat = GRN_LOADER_TOKEN;\
700   str++;\
701 } while (0)
702 
703 static void
json_read(grn_ctx * ctx,grn_loader * loader,const char * str,unsigned int str_len)704 json_read(grn_ctx *ctx, grn_loader *loader, const char *str, unsigned int str_len)
705 {
706   const char *const beg = str;
707   char c;
708   int len;
709   const char *se = str + str_len;
710   while (str < se) {
711     c = *str;
712     switch (loader->stat) {
713     case GRN_LOADER_BEGIN :
714       if ((len = grn_isspace(str, ctx->encoding))) {
715         str += len;
716         continue;
717       }
718       switch (c) {
719       case '[' :
720         JSON_READ_OPEN_BRACKET();
721         break;
722       case '{' :
723         JSON_READ_OPEN_BRACE();
724         break;
725       default :
726         ERR(GRN_INVALID_ARGUMENT,
727             "JSON must start with '[' or '{': <%.*s>", str_len, beg);
728         loader->stat = GRN_LOADER_END;
729         break;
730       }
731       break;
732     case GRN_LOADER_TOKEN :
733       if ((len = grn_isspace(str, ctx->encoding))) {
734         str += len;
735         continue;
736       }
737       switch (c) {
738       case '"' :
739         loader->stat = GRN_LOADER_STRING;
740         values_add(ctx, loader);
741         str++;
742         break;
743       case '[' :
744         JSON_READ_OPEN_BRACKET();
745         break;
746       case '{' :
747         JSON_READ_OPEN_BRACE();
748         break;
749       case ':' :
750         str++;
751         break;
752       case ',' :
753         str++;
754         break;
755       case ']' :
756         bracket_close(ctx, loader);
757         loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
758         if (ctx->rc == GRN_CANCEL) {
759           loader->stat = GRN_LOADER_END;
760         }
761         str++;
762         break;
763       case '}' :
764         brace_close(ctx, loader);
765         loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
766         if (ctx->rc == GRN_CANCEL) {
767           loader->stat = GRN_LOADER_END;
768         }
769         str++;
770         break;
771       case '+' : case '-' : case '0' : case '1' : case '2' : case '3' :
772       case '4' : case '5' : case '6' : case '7' : case '8' : case '9' :
773         loader->stat = GRN_LOADER_NUMBER;
774         values_add(ctx, loader);
775         break;
776       default :
777         if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('_' == c)) {
778           loader->stat = GRN_LOADER_SYMBOL;
779           values_add(ctx, loader);
780         } else {
781           if ((len = grn_charlen(ctx, str, se))) {
782             GRN_LOG(ctx, GRN_LOG_ERROR, "ignored invalid char('%c') at", c);
783             GRN_LOG(ctx, GRN_LOG_ERROR, "%.*s", (int)(str - beg) + len, beg);
784             GRN_LOG(ctx, GRN_LOG_ERROR, "%*s", (int)(str - beg) + 1, "^");
785             str += len;
786           } else {
787             GRN_LOG(ctx, GRN_LOG_ERROR, "ignored invalid char(\\x%.2x) after", c);
788             GRN_LOG(ctx, GRN_LOG_ERROR, "%.*s", (int)(str - beg), beg);
789             str = se;
790           }
791         }
792         break;
793       }
794       break;
795     case GRN_LOADER_SYMBOL :
796       if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') ||
797           ('0' <= c && c <= '9') || ('_' == c)) {
798         GRN_TEXT_PUTC(ctx, loader->last, c);
799         str++;
800       } else {
801         char *v = GRN_TEXT_VALUE(loader->last);
802         switch (*v) {
803         case 'n' :
804           if (GRN_TEXT_LEN(loader->last) == 4 && !memcmp(v, "null", 4)) {
805             loader->last->header.domain = GRN_DB_VOID;
806             GRN_BULK_REWIND(loader->last);
807           }
808           break;
809         case 't' :
810           if (GRN_TEXT_LEN(loader->last) == 4 && !memcmp(v, "true", 4)) {
811             loader->last->header.domain = GRN_DB_BOOL;
812             GRN_BOOL_SET(ctx, loader->last, GRN_TRUE);
813           }
814           break;
815         case 'f' :
816           if (GRN_TEXT_LEN(loader->last) == 5 && !memcmp(v, "false", 5)) {
817             loader->last->header.domain = GRN_DB_BOOL;
818             GRN_BOOL_SET(ctx, loader->last, GRN_FALSE);
819           }
820           break;
821         default :
822           break;
823         }
824         loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
825       }
826       break;
827     case GRN_LOADER_NUMBER :
828       switch (c) {
829       case '+' : case '-' : case '.' : case 'e' : case 'E' :
830       case '0' : case '1' : case '2' : case '3' : case '4' :
831       case '5' : case '6' : case '7' : case '8' : case '9' :
832         GRN_TEXT_PUTC(ctx, loader->last, c);
833         str++;
834         break;
835       default :
836         {
837           const char *cur, *str = GRN_BULK_HEAD(loader->last);
838           const char *str_end = GRN_BULK_CURR(loader->last);
839           int64_t i = grn_atoll(str, str_end, &cur);
840           if (cur == str_end) {
841             loader->last->header.domain = GRN_DB_INT64;
842             GRN_INT64_SET(ctx, loader->last, i);
843           } else if (cur != str) {
844             uint64_t i = grn_atoull(str, str_end, &cur);
845             if (cur == str_end) {
846               loader->last->header.domain = GRN_DB_UINT64;
847               GRN_UINT64_SET(ctx, loader->last, i);
848             } else if (cur != str) {
849               double d;
850               char *end;
851               grn_obj buf;
852               GRN_TEXT_INIT(&buf, 0);
853               GRN_TEXT_PUT(ctx, &buf, str, GRN_BULK_VSIZE(loader->last));
854               GRN_TEXT_PUTC(ctx, &buf, '\0');
855               errno = 0;
856               d = strtod(GRN_TEXT_VALUE(&buf), &end);
857               if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
858                 loader->last->header.domain = GRN_DB_FLOAT;
859                 GRN_FLOAT_SET(ctx, loader->last, d);
860               }
861               GRN_OBJ_FIN(ctx, &buf);
862             }
863           }
864         }
865         loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
866         break;
867       }
868       break;
869     case GRN_LOADER_STRING :
870       switch (c) {
871       case '\\' :
872         loader->stat = GRN_LOADER_STRING_ESC;
873         str++;
874         break;
875       case '"' :
876         str++;
877         loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
878         /*
879         *(GRN_BULK_CURR(loader->last)) = '\0';
880         GRN_LOG(ctx, GRN_LOG_ALERT, "read str(%s)", GRN_TEXT_VALUE(loader->last));
881         */
882         break;
883       default :
884         if ((len = grn_charlen(ctx, str, se))) {
885           GRN_TEXT_PUT(ctx, loader->last, str, len);
886           str += len;
887         } else {
888           GRN_LOG(ctx, GRN_LOG_ERROR, "ignored invalid char(\\x%.2x) after", c);
889           GRN_LOG(ctx, GRN_LOG_ERROR, "%.*s", (int)(str - beg), beg);
890           str = se;
891         }
892         break;
893       }
894       break;
895     case GRN_LOADER_STRING_ESC :
896       switch (c) {
897       case 'b' :
898         GRN_TEXT_PUTC(ctx, loader->last, '\b');
899         loader->stat = GRN_LOADER_STRING;
900         break;
901       case 'f' :
902         GRN_TEXT_PUTC(ctx, loader->last, '\f');
903         loader->stat = GRN_LOADER_STRING;
904         break;
905       case 'n' :
906         GRN_TEXT_PUTC(ctx, loader->last, '\n');
907         loader->stat = GRN_LOADER_STRING;
908         break;
909       case 'r' :
910         GRN_TEXT_PUTC(ctx, loader->last, '\r');
911         loader->stat = GRN_LOADER_STRING;
912         break;
913       case 't' :
914         GRN_TEXT_PUTC(ctx, loader->last, '\t');
915         loader->stat = GRN_LOADER_STRING;
916         break;
917       case 'u' :
918         loader->stat = GRN_LOADER_UNICODE0;
919         break;
920       default :
921         GRN_TEXT_PUTC(ctx, loader->last, c);
922         loader->stat = GRN_LOADER_STRING;
923         break;
924       }
925       str++;
926       break;
927     case GRN_LOADER_UNICODE0 :
928       switch (c) {
929       case '0' : case '1' : case '2' : case '3' : case '4' :
930       case '5' : case '6' : case '7' : case '8' : case '9' :
931         loader->unichar = (c - '0') * 0x1000;
932         break;
933       case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
934         loader->unichar = (c - 'a' + 10) * 0x1000;
935         break;
936       case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
937         loader->unichar = (c - 'A' + 10) * 0x1000;
938         break;
939       default :
940         ;// todo : error
941       }
942       loader->stat = GRN_LOADER_UNICODE1;
943       str++;
944       break;
945     case GRN_LOADER_UNICODE1 :
946       switch (c) {
947       case '0' : case '1' : case '2' : case '3' : case '4' :
948       case '5' : case '6' : case '7' : case '8' : case '9' :
949         loader->unichar += (c - '0') * 0x100;
950         break;
951       case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
952         loader->unichar += (c - 'a' + 10) * 0x100;
953         break;
954       case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
955         loader->unichar += (c - 'A' + 10) * 0x100;
956         break;
957       default :
958         ;// todo : error
959       }
960       loader->stat = GRN_LOADER_UNICODE2;
961       str++;
962       break;
963     case GRN_LOADER_UNICODE2 :
964       switch (c) {
965       case '0' : case '1' : case '2' : case '3' : case '4' :
966       case '5' : case '6' : case '7' : case '8' : case '9' :
967         loader->unichar += (c - '0') * 0x10;
968         break;
969       case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
970         loader->unichar += (c - 'a' + 10) * 0x10;
971         break;
972       case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
973         loader->unichar += (c - 'A' + 10) * 0x10;
974         break;
975       default :
976         ;// todo : error
977       }
978       loader->stat = GRN_LOADER_UNICODE3;
979       str++;
980       break;
981     case GRN_LOADER_UNICODE3 :
982       switch (c) {
983       case '0' : case '1' : case '2' : case '3' : case '4' :
984       case '5' : case '6' : case '7' : case '8' : case '9' :
985         loader->unichar += (c - '0');
986         break;
987       case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
988         loader->unichar += (c - 'a' + 10);
989         break;
990       case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
991         loader->unichar += (c - 'A' + 10);
992         break;
993       default :
994         ;// todo : error
995       }
996       {
997         uint32_t u = loader->unichar;
998         if (u < 0x80) {
999           GRN_TEXT_PUTC(ctx, loader->last, u);
1000         } else {
1001           if (u < 0x800) {
1002             GRN_TEXT_PUTC(ctx, loader->last, ((u >> 6) & 0x1f) | 0xc0);
1003           } else {
1004             GRN_TEXT_PUTC(ctx, loader->last, (u >> 12) | 0xe0);
1005             GRN_TEXT_PUTC(ctx, loader->last, ((u >> 6) & 0x3f) | 0x80);
1006           }
1007           GRN_TEXT_PUTC(ctx, loader->last, (u & 0x3f) | 0x80);
1008         }
1009       }
1010       loader->stat = GRN_LOADER_STRING;
1011       str++;
1012       break;
1013     case GRN_LOADER_END :
1014       str = se;
1015       break;
1016     }
1017   }
1018 }
1019 
1020 #undef JSON_READ_OPEN_BRACKET
1021 #undef JSON_READ_OPEN_BRACE
1022 
1023 /*
1024  * grn_loader_parse_columns parses a columns parameter.
1025  * Columns except _id and _key are appended to loader->columns.
1026  * If it contains _id or _key, loader->id_offset or loader->key_offset is set.
1027  */
1028 static grn_rc
grn_loader_parse_columns(grn_ctx * ctx,grn_loader * loader,const char * str,unsigned int str_size)1029 grn_loader_parse_columns(grn_ctx *ctx, grn_loader *loader,
1030                          const char *str, unsigned int str_size)
1031 {
1032   const char *ptr = str, *ptr_end = ptr + str_size, *rest;
1033   const char *tokens[256], *token_end;
1034   while (ptr < ptr_end) {
1035     int i, n = grn_tokenize(ptr, ptr_end - ptr, tokens, 256, &rest);
1036     for (i = 0; i < n; i++) {
1037       grn_obj *column;
1038       token_end = tokens[i];
1039       while (ptr < token_end && (' ' == *ptr || ',' == *ptr)) {
1040         ptr++;
1041       }
1042       column = grn_obj_column(ctx, loader->table, ptr, token_end - ptr);
1043       if (!column) {
1044         ERR(GRN_INVALID_ARGUMENT, "nonexistent column: <%.*s>",
1045             (int)(token_end - ptr), ptr);
1046         return ctx->rc;
1047       }
1048       if (name_equal(ptr, token_end - ptr, GRN_COLUMN_NAME_ID)) {
1049         grn_obj_unlink(ctx, column);
1050         if (loader->id_offset != -1 || loader->key_offset != -1) {
1051           /* _id and _key must not appear more than once. */
1052           if (loader->id_offset != -1) {
1053             ERR(GRN_INVALID_ARGUMENT,
1054                 "duplicated id and key columns: <%s> at %d and <%s> at %d",
1055                 GRN_COLUMN_NAME_ID, i,
1056                 GRN_COLUMN_NAME_ID, loader->id_offset);
1057           } else {
1058             ERR(GRN_INVALID_ARGUMENT,
1059                 "duplicated id and key columns: <%s> at %d and <%s> at %d",
1060                 GRN_COLUMN_NAME_ID, i,
1061                 GRN_COLUMN_NAME_KEY, loader->key_offset);
1062           }
1063           return ctx->rc;
1064         }
1065         loader->id_offset = i;
1066       } else if (name_equal(ptr, token_end - ptr, GRN_COLUMN_NAME_KEY)) {
1067         grn_obj_unlink(ctx, column);
1068         if (loader->id_offset != -1 || loader->key_offset != -1) {
1069           /* _id and _key must not appear more than once. */
1070           if (loader->id_offset != -1) {
1071             ERR(GRN_INVALID_ARGUMENT,
1072                 "duplicated id and key columns: <%s> at %d and <%s> at %d",
1073                 GRN_COLUMN_NAME_KEY, i,
1074                 GRN_COLUMN_NAME_ID, loader->id_offset);
1075           } else {
1076             ERR(GRN_INVALID_ARGUMENT,
1077                 "duplicated id and key columns: <%s> at %d and <%s> at %d",
1078                 GRN_COLUMN_NAME_KEY, i,
1079                 GRN_COLUMN_NAME_KEY, loader->key_offset);
1080           }
1081           return ctx->rc;
1082         }
1083         loader->key_offset = i;
1084       } else {
1085         GRN_PTR_PUT(ctx, &loader->columns, column);
1086       }
1087       ptr = token_end;
1088     }
1089     ptr = rest;
1090   }
1091   switch (loader->table->header.type) {
1092   case GRN_TABLE_HASH_KEY :
1093   case GRN_TABLE_PAT_KEY :
1094   case GRN_TABLE_DAT_KEY :
1095     if (loader->id_offset == -1 && loader->key_offset == -1) {
1096       ERR(GRN_INVALID_ARGUMENT, "missing id or key column");
1097       return ctx->rc;
1098     }
1099     break;
1100   }
1101   return ctx->rc;
1102 }
1103 
1104 static grn_com_addr *addr;
1105 
1106 void
grn_load_internal(grn_ctx * ctx,grn_load_input * input)1107 grn_load_internal(grn_ctx *ctx, grn_load_input *input)
1108 {
1109   grn_loader *loader = &ctx->impl->loader;
1110 
1111   loader->emit_level = input->emit_level;
1112   if (ctx->impl->edge) {
1113     grn_edge *edge = grn_edges_add_communicator(ctx, addr);
1114     grn_obj *msg = grn_msg_open(ctx, edge->com, &ctx->impl->edge->send_old);
1115     /* build msg */
1116     grn_edge_dispatch(ctx, edge, msg);
1117   }
1118   if (input->table.length > 0) {
1119     grn_ctx_loader_clear(ctx);
1120     loader->input_type = input->type;
1121     if (grn_db_check_name(ctx, input->table.value, input->table.length)) {
1122       GRN_DB_CHECK_NAME_ERR("[table][load]",
1123                             input->table.value,
1124                             (int)(input->table.length));
1125       loader->stat = GRN_LOADER_END;
1126       return;
1127     }
1128     loader->table = grn_ctx_get(ctx, input->table.value, input->table.length);
1129     if (!loader->table) {
1130       ERR(GRN_INVALID_ARGUMENT,
1131           "nonexistent table: <%.*s>",
1132           (int)(input->table.length),
1133           input->table.value);
1134       loader->stat = GRN_LOADER_END;
1135       return;
1136     }
1137     if (input->columns.length > 0) {
1138       grn_rc rc = grn_loader_parse_columns(ctx,
1139                                            loader,
1140                                            input->columns.value,
1141                                            input->columns.length);
1142       if (rc != GRN_SUCCESS) {
1143         loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
1144         loader->stat = GRN_LOADER_END;
1145         return;
1146       }
1147       loader->columns_status = GRN_LOADER_COLUMNS_SET;
1148     }
1149     if (input->if_exists.length > 0) {
1150       grn_obj *v;
1151       GRN_EXPR_CREATE_FOR_QUERY(ctx, loader->table, loader->ifexists, v);
1152       if (loader->ifexists && v) {
1153         grn_expr_parse(ctx,
1154                        loader->ifexists,
1155                        input->if_exists.value,
1156                        input->if_exists.length,
1157                        NULL, GRN_OP_EQUAL, GRN_OP_AND,
1158                        GRN_EXPR_SYNTAX_SCRIPT|GRN_EXPR_ALLOW_UPDATE);
1159       }
1160     }
1161     if (input->each.length > 0) {
1162       grn_obj *v;
1163       GRN_EXPR_CREATE_FOR_QUERY(ctx, loader->table, loader->each, v);
1164       if (loader->each && v) {
1165         grn_expr_parse(ctx, loader->each,
1166                        input->each.value,
1167                        input->each.length,
1168                        NULL, GRN_OP_EQUAL, GRN_OP_AND,
1169                        GRN_EXPR_SYNTAX_SCRIPT|GRN_EXPR_ALLOW_UPDATE);
1170       }
1171     }
1172     loader->output_ids = input->output_ids;
1173     loader->output_errors = input->output_errors;
1174   } else {
1175     if (!loader->table) {
1176       ERR(GRN_INVALID_ARGUMENT, "mandatory \"table\" parameter is absent");
1177       loader->stat = GRN_LOADER_END;
1178       return;
1179     }
1180   }
1181   switch (loader->input_type) {
1182   case GRN_CONTENT_JSON :
1183     json_read(ctx, loader, input->values.value, input->values.length);
1184     break;
1185   case GRN_CONTENT_NONE :
1186   case GRN_CONTENT_TSV :
1187   case GRN_CONTENT_XML :
1188   case GRN_CONTENT_MSGPACK :
1189   case GRN_CONTENT_GROONGA_COMMAND_LIST :
1190     ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "unsupported input_type");
1191     loader->stat = GRN_LOADER_END;
1192     // todo
1193     break;
1194   }
1195 }
1196 
1197 grn_rc
grn_load(grn_ctx * ctx,grn_content_type input_type,const char * table,unsigned int table_len,const char * columns,unsigned int columns_len,const char * values,unsigned int values_len,const char * ifexists,unsigned int ifexists_len,const char * each,unsigned int each_len)1198 grn_load(grn_ctx *ctx, grn_content_type input_type,
1199          const char *table, unsigned int table_len,
1200          const char *columns, unsigned int columns_len,
1201          const char *values, unsigned int values_len,
1202          const char *ifexists, unsigned int ifexists_len,
1203          const char *each, unsigned int each_len)
1204 {
1205   if (!ctx || !ctx->impl) {
1206     ERR(GRN_INVALID_ARGUMENT, "db not initialized");
1207     return ctx->rc;
1208   }
1209   GRN_API_ENTER;
1210   {
1211     grn_load_input input;
1212     input.type = input_type;
1213     input.table.value = table;
1214     input.table.length = table_len;
1215     input.columns.value = columns;
1216     input.columns.length = columns_len;
1217     input.values.value = values;
1218     input.values.length = values_len;
1219     input.if_exists.value = ifexists;
1220     input.if_exists.length = ifexists_len;
1221     input.each.value = each;
1222     input.each.length = each_len;
1223     input.output_ids = GRN_FALSE;
1224     input.output_errors = GRN_FALSE;
1225     input.emit_level = 1;
1226     grn_load_internal(ctx, &input);
1227   }
1228   GRN_API_RETURN(ctx->rc);
1229 }
1230