static bool tnt_sql_kv_select(struct tnt_sql *sql, struct tnt_tuple *tu, int32_t *index) { struct tnt_tk *key = NULL; bool rc = tnt_sql_keyval(sql, tu, true, &key); if (rc == false) return false; if (*index == -1) *index = TNT_TK_I32(key); else if (*index != TNT_TK_I32(key)) return tnt_sql_error(sql, key, "select key values must refer to the same index"); return true; }
static int nb_config_readint(struct nb_config *cfg, int *v) { struct tnt_tk *tk; if (nb_config_expect(cfg, TNT_TK_NUM32, &tk) == -1) return -1; *v = TNT_TK_I32(tk); return 0; }
static bool tnt_sql_keyval(struct tnt_sql *sql, struct tnt_tuple *tu, bool key, struct tnt_tk **kt) { /* key */ struct tnt_tk *k = NULL; if (key && (!tnt_sqltkv(sql, TNT_TK_KEY, &k) || !tnt_sqltk(sql, '='))) return false; if (kt) *kt = k; /* value */ struct tnt_tk *v = NULL; if (tnt_lex(sql->l, &v) == TNT_TK_ERROR) return tnt_sql_error(sql, NULL, "%s", sql->l->error); switch (v->tk) { case TNT_TK_NUM32: tnt_tuple_add(tu, (char*)&TNT_TK_I32(v), 4); break; case TNT_TK_NUM64: tnt_tuple_add(tu, (char*)&TNT_TK_I64(v), 8); break; case TNT_TK_STRING: tnt_tuple_add(tu, (char*)TNT_TK_S(v)->data, TNT_TK_S(v)->size); break; default: return tnt_sql_error(sql, k, "expected NUM32 or NUM64 or STRING"); } return true; }
static bool tnt_sql_stmt(struct tnt_sql *sql) { struct tnt_tuple tu; struct tnt_list tuples; struct tnt_stream update; tnt_tuple_init(&tu); tnt_list_init(&tuples); tnt_buf(&update); int flags = 0; struct tnt_tk *tk = NULL, *tn = NULL; bool rc = false; switch (tnt_lex(sql->l, &tk)) { /* <INSERT|REPLACE> [INTO] TABLE VALUES ( list ) */ case TNT_TK_INSERT: case TNT_TK_REPLACE: tnt_sqltry(sql, TNT_TK_INTO); if (sql->error) goto error; tnt_expect(tnt_sqltkv(sql, TNT_TK_TABLE, &tn)); tnt_expect(tnt_sqltk(sql, TNT_TK_VALUES)); tnt_expect(tnt_sqltk(sql, '(')); while (1) { tnt_expect(tnt_sql_kv(sql, &tu, false)); if (tnt_sqltry(sql, ',')) continue; if (sql->error) goto error; break; } flags = TNT_FLAG_ADD; if (tk->tk == TNT_TK_REPLACE) flags = TNT_FLAG_REPLACE; tnt_expect(tnt_sqltk(sql, ')')); tnt_expect(tnt_sqltk(sql, TNT_TK_EOF)); if (tnt_insert(sql->s, TNT_TK_I32(tn), flags, &tu) == -1) { tnt_sql_error(sql, tk, "insert failed"); goto error; } break; /* UPDATE TABLE SET operations WHERE predicate */ case TNT_TK_UPDATE: if (!tnt_sql_stmt_update(sql, &tu, &update)) goto error; break; /* DELETE FROM TABLE WHERE predicate */ case TNT_TK_DELETE: tnt_expect(tnt_sqltk(sql, TNT_TK_FROM)); tnt_expect(tnt_sqltkv(sql, TNT_TK_TABLE, &tn)); tnt_expect(tnt_sqltk(sql, TNT_TK_WHERE)); /* predicate */ tnt_expect(tnt_sql_kv(sql, &tu, true)); tnt_expect(tnt_sqltk(sql, TNT_TK_EOF)); if (tnt_delete(sql->s, TNT_TK_I32(tn), 0, &tu) == -1) { tnt_sql_error(sql, tk, "delete failed"); goto error; } break; /* SELECT * FROM TABLE WHERE predicate OR predicate... LIMIT NUM */ case TNT_TK_SELECT: { tnt_expect(tnt_sqltk(sql, '*')); tnt_expect(tnt_sqltk(sql, TNT_TK_FROM)); tnt_expect(tnt_sqltkv(sql, TNT_TK_TABLE, &tn)); tnt_expect(tnt_sqltk(sql, TNT_TK_WHERE)); int32_t index = -1; while (1) { struct tnt_tuple *tup = tnt_list_at(&tuples, NULL); while (1) { tnt_expect(tnt_sql_kv_select(sql, tup, &index)); if (tnt_sqltry(sql, TNT_TK_AND)) continue; if (sql->error) goto error; break; } if (tnt_sqltry(sql, TNT_TK_OR)) continue; if (sql->error) goto error; break; } uint32_t limit = UINT32_MAX; if (tnt_sqltry(sql, TNT_TK_LIMIT)) { struct tnt_tk *ltk; tnt_expect(tnt_sqltkv(sql, TNT_TK_NUM32, <k)); limit = TNT_TK_I32(ltk); } else if (sql->error) goto error; tnt_expect(tnt_sqltk(sql, TNT_TK_EOF)); if (tnt_select(sql->s, TNT_TK_I32(tn), index, 0, limit, &tuples) == -1) { tnt_sql_error(sql, tk, "select failed"); goto error; } break; } /* CALL NAME[{.NAME}+](STRING [{,STRING}+]) */ case TNT_TK_CALL: { char proc[512]; int len = 0; while (1) { struct tnt_tk *name = NULL; tnt_lex_idonly(sql->l, true); tnt_expect(tnt_sqltkv(sql, TNT_TK_ID, &name)); tnt_lex_idonly(sql->l, false); len += snprintf(proc + len, sizeof(proc) - len, "%.*s", (int)TNT_TK_S(name)->size, TNT_TK_S(name)->data); if (!tnt_sqltry(sql, '.')) break; if (sql->error) goto error; len += snprintf(proc + len, sizeof(proc) - len, "%s", "."); } tnt_expect(tnt_sqltk(sql, '(')); if (tnt_sqltry(sql, ')')) goto noargs; if (sql->error) goto error; while (1) { tnt_expect(tnt_sql_kv(sql, &tu, false)); if (tnt_sqltry(sql, ',')) continue; if (sql->error) goto error; break; } tnt_expect(tnt_sqltk(sql, ')')); noargs: tnt_expect(tnt_sqltk(sql, TNT_TK_EOF)); if (tnt_call(sql->s, 0, proc, &tu) == -1) { tnt_sql_error(sql, tk, "call failed"); goto error; } break; } /* PING */ case TNT_TK_PING: tnt_expect(tnt_sqltk(sql, TNT_TK_EOF)); if (tnt_ping(sql->s) == -1) { tnt_sql_error(sql, tk, "ping failed"); goto error; } break; case TNT_TK_EOF: break; case TNT_TK_ERROR: return tnt_sql_error(sql, tk, "%s", sql->l->error); default: return tnt_sql_error(sql, tk, "insert, replace, update, delete, select, call, ping are expected"); } rc = true; error: tnt_tuple_free(&tu); tnt_list_free(&tuples); tnt_stream_free(&update); return rc; }
static bool tnt_sql_stmt_update(struct tnt_sql *sql, struct tnt_tuple *tu, struct tnt_stream *u) { /* UPDATE TABLE SET operations WHERE predicate */ bool rc = false; struct tnt_tk *tn = NULL; tnt_expect(tnt_sqltkv(sql, TNT_TK_TABLE, &tn)); tnt_expect(tnt_sqltk(sql, TNT_TK_SET)); while (1) { struct tnt_tk *k = NULL; tnt_expect(tnt_sqltkv(sql, TNT_TK_KEY, &k)); tnt_expect(tnt_sqltk(sql, '=')); struct tnt_tk *v; switch (tnt_lex(sql->l, &v)) { /* k = k op v */ case TNT_TK_KEY: if (TNT_TK_I32(k) != TNT_TK_I32(v)) { tnt_sql_error(sql, k, "can't update on different keys"); goto error; } int ut; switch (tnt_lex(sql->l, &v)) { case TNT_TK_ERROR: tnt_sql_error(sql, k, "%s", sql->l->error); goto error; case '+': ut = TNT_UPDATE_ADD; break; case '&': ut = TNT_UPDATE_AND; break; case '^': ut = TNT_UPDATE_XOR; break; case '|': ut = TNT_UPDATE_OR; break; default: tnt_sql_error(sql, k, "bad update operation"); goto error; } tnt_expect(tnt_sqltkv(sql, TNT_TK_NUM32, &v)); tnt_update_arith(u, TNT_TK_I32(k), ut, TNT_TK_I32(v)); break; /* k = string */ case TNT_TK_STRING: tnt_update_assign(u, TNT_TK_I32(k), (char*)TNT_TK_S(v)->data, TNT_TK_S(v)->size); break; /* k = num32 */ case TNT_TK_NUM32: tnt_update_assign(u, TNT_TK_I32(k), (char*)&TNT_TK_I32(v), 4); break; /* k = num64 */ case TNT_TK_NUM64: tnt_update_assign(u, TNT_TK_I64(k), (char*)&TNT_TK_I64(v), 8); break; /* k = splice(k, a, b) */ case TNT_TK_SPLICE: { struct tnt_tk *field = NULL, *off = NULL, *len = NULL, *list = NULL; tnt_expect(tnt_sqltk(sql, '(')); tnt_expect(tnt_sqltkv(sql, TNT_TK_KEY, &field)); if (TNT_TK_I32(k) != TNT_TK_I32(field)) { tnt_sql_error(sql, k, "can't update on different keys"); goto error; } tnt_expect(tnt_sqltk(sql, ',')); tnt_expect(tnt_sqltkv(sql, TNT_TK_NUM32, &off)); tnt_expect(tnt_sqltk(sql, ',')); tnt_expect(tnt_sqltkv(sql, TNT_TK_NUM32, &len)); tnt_expect(tnt_sqltk(sql, ',')); tnt_expect(tnt_sqltkv(sql, TNT_TK_STRING, &list)); tnt_expect(tnt_sqltk(sql, ')')); tnt_update_splice(u, TNT_TK_I32(k), TNT_TK_I32(off), TNT_TK_I32(len), (char*)TNT_TK_S(list)->data, TNT_TK_S(list)->size); break; } case TNT_TK_ERROR: tnt_sql_error(sql, k, "%s", sql->l->error); goto error; } if (tnt_sqltry(sql, ',')) continue; if (sql->error) goto error; break; } tnt_expect(tnt_sqltk(sql, TNT_TK_WHERE)); /* predicate */ tnt_expect(tnt_sql_kv(sql, tu, true)); tnt_expect(tnt_sqltk(sql, TNT_TK_EOF)); if (tnt_update(sql->s, TNT_TK_I32(tn), 0, tu, u) == -1) { tnt_sql_error(sql, tn, "update failed"); goto error; } rc = true; error: return rc; }