/* * tnt_query_is() * * Tells if the supplied query should be processed as SQL. * * q - sql query string * qsize - query size * * returns 1 if yes, 0 otherwise. */ int tnt_query_is(char *q, size_t qsize) { struct tnt_lex l; if (!tnt_lex_init(&l, tnt_sql_keywords, (unsigned char*)q, qsize)) return 0; int rc = 0; struct tnt_tk *tk; switch (tnt_lex(&l, &tk)) { case TNT_TK_ERROR: case TNT_TK_EOF: break; default: if (tk->tk == TNT_TK_PING || tk->tk == TNT_TK_INSERT || tk->tk == TNT_TK_REPLACE || tk->tk == TNT_TK_UPDATE || tk->tk == TNT_TK_SELECT || tk->tk == TNT_TK_DELETE || tk->tk == TNT_TK_CALL) rc = 1; break; } tnt_lex_free(&l); return rc; }
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_try(struct tnt_sql *sql, int tk, struct tnt_tk **tkp) { struct tnt_tk *tkp_ = NULL; int tk_ = tnt_lex(sql->l, &tkp_); if (tk_ == TNT_TK_ERROR) return tnt_sql_error(sql, NULL, "%s", sql->l->error); if (tk_ != tk) { tnt_lex_push(sql->l, tkp_); return false; } if (tkp) *tkp = tkp_; return true; }
static bool tnt_sql_tk(struct tnt_sql *sql, int tk, struct tnt_tk **tkp) { struct tnt_tk *tkp_ = NULL; int tk_ = tnt_lex(sql->l, &tkp_); if (tk_ == TNT_TK_ERROR) return tnt_sql_error(sql, NULL, "%s", sql->l->error); if (tk_ != tk) { if (tk < 0xff && ispunct(tk)) return tnt_sql_error(sql, tkp_, "expected '%c'", tk); return tnt_sql_error(sql, tkp_, "expected '%s'", tnt_lex_nameof(sql->l, tk)); } if (tkp) *tkp = tkp_; return true; }
static int nb_config_expect(struct nb_config *cfg, int tk, struct tnt_tk **tkp) { struct tnt_tk *tkp_ = NULL; int tk_ = tnt_lex(&cfg->lex, &tkp_); if (tk_ == TNT_TK_ERROR) return nb_config_error(cfg, NULL, "%s", cfg->lex.error); if (tk_ != tk) { if (tk < 0xff && ispunct(tk)) return nb_config_error(cfg, tkp_, "expected '%c'", tk); return nb_config_error(cfg, tkp_, "expected '%s'", tnt_lex_nameof(&cfg->lex, tk)); } if (tkp) *tkp = tkp_; return 0; }
static int nb_config_process(struct nb_config *cfg) { struct tnt_tk *tk; if (nb_config_expect(cfg, NB_TK_CONFIGURATION, NULL) == -1) return -1; if (nb_config_expect(cfg, '{', NULL) == -1) return -1; int eoc = 0; while (!eoc) { tnt_lex(&cfg->lex, &tk); if (nb_config_read(cfg, tk) == 0) continue; if (tk->tk == TNT_TK_PUNCT && tk->v.i32 == '}') eoc = 1; else return nb_config_error(cfg, tk, "unknown option"); } return 0; }
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; }