diff options
-rw-r--r-- | db.c | 39 | ||||
-rw-r--r-- | db.h | 6 | ||||
-rw-r--r-- | query.c | 229 |
3 files changed, 129 insertions, 145 deletions
@@ -30,6 +30,12 @@ sqlite3 *db = NULL; sqlite3_stmt *stmt_global_stat = NULL; +sqlite3_stmt *stmt_personal_stat = NULL; + +sqlite3_stmt *stmt_search = NULL; + +sqlite3_stmt *stmt_random = NULL; + void db_init(void) { int r; r = sqlite3_open(cmd.db_path, &db); @@ -76,6 +82,27 @@ void db_init(void) { errmsg = (char *) sqlite3_errstr(r); goto sql_err; } + + if ((r = sqlite3_prepare_v2(db, "SELECT i FROM stats WHERE user = ?", -1, &stmt_personal_stat, NULL))) { + errmsg = (char *) sqlite3_errstr(r); + goto sql_err; + } + + if ((r = sqlite3_prepare_v2(db, "SELECT id, t, url FROM says WHERE t LIKE ? LIMIT 10;", + -1, + &stmt_search, + NULL))) { + errmsg = (char *) sqlite3_errstr(r); + goto sql_err; + } + + if ((r = sqlite3_prepare_v2(db, "SELECT id, t, url FROM says ORDER BY RANDOM() LIMIT 10;", + -1, + &stmt_random, + NULL))) { + errmsg = (char *) sqlite3_errstr(r); + goto sql_err; + } } void db_close(void) { @@ -85,6 +112,18 @@ void db_close(void) { sqlite3_finalize(stmt_global_stat); stmt_global_stat = NULL; } + if (stmt_personal_stat) { + sqlite3_finalize(stmt_personal_stat); + stmt_personal_stat = NULL; + } + if (stmt_random) { + sqlite3_finalize(stmt_random); + stmt_random = NULL; + } + if (stmt_search) { + sqlite3_finalize(stmt_search); + stmt_search = NULL; + } sqlite3_close(db); db = NULL; } @@ -15,6 +15,12 @@ extern sqlite3_stmt *stmt_global_stat; +extern sqlite3_stmt *stmt_personal_stat; + +extern sqlite3_stmt *stmt_random; + +extern sqlite3_stmt *stmt_search; + extern sqlite3 *db; void db_init(void); @@ -13,17 +13,6 @@ #include <errno.h> #include <assert.h> -struct result { - char id[32]; - /* Title in selection */ - char *title; - /* Description in selection */ - char *description; - /* Text after sending */ - char *text; - char *url; -}; - static void cb_answer(bool successful, struct TdObject *result, struct TdError *error, void *cb_arg) { if (!successful) { LOGEV("Cannot answer inline request: %s.", @@ -31,182 +20,132 @@ static void cb_answer(bool successful, struct TdObject *result, struct TdError * } } +static struct TdInputInlineQueryResultArticle *create_inline_result(char *id, + char *title, + char *descr, + char *text) { + struct TdInputInlineQueryResultArticle *r = TdCreateObjectInputInlineQueryResultArticle( + id, + NULL, + false, + title, + descr, + NULL, + 0, + 0, + NULL, + (struct TdInputMessageContent *) TdCreateObjectInputMessageText( + TdCreateObjectFormattedText(text, + (struct TdVectorTextEntity *) TdCreateObjectVectorObject(0, + NULL)), + true, + false + )); + /* No allocation fail detection here */ + return r; +} + int handle_inline(struct TdUpdateNewInlineQuery *update) { - struct result results[11]; - memset(results, 0, sizeof(results)); - sqlite3_stmt *stmt; int r; + /* May return < 10 rows. Start with 0, so we can free the initial stat one if that produces an error. */ + int effective_items_count = 0; + struct TdInputInlineQueryResultArticle *results_inline[11]; const bool query = update->query_; + char *query_str = NULL; + int personal_stat = 0; + char id_temp[32]; + char msg_stat[32]; + sqlite3_stmt *stmt_query = query ? stmt_search : stmt_random; - if ((r = sqlite3_prepare_v2(db, "SELECT i FROM stats WHERE user = ?", -1, &stmt, NULL))) { - goto sql_err; - sql_err: - snprintf(results[0].id, 32, "e%d", r); - char *msg = (char *) sqlite3_errstr(r); - LOGEV("Cannot query: %s.", msg); - results[0].title = "Error!"; - results[0].text = msg; - results[0].description = msg; - if (stmt) sqlite3_finalize(stmt); - goto answer; - } + memset(results_inline, 0, sizeof(results_inline)); - if ((r = sqlite3_bind_int64(stmt, 1, update->sender_user_id_))) { + if ((r = sqlite3_bind_int64(stmt_personal_stat, 1, update->sender_user_id_))) { goto sql_err; + sql_err: + LOGEV("Cannot query: %s.", sqlite3_errstr(r)); + for (int i = 0; i < effective_items_count; i ++) { + TdDestroyObjectInputInlineQueryResultArticle(results_inline[i]); + } + goto cleanup; } - char msg_stat[32]; - int st; - switch (r = sqlite3_step(stmt)) { + switch (r = sqlite3_step(stmt_personal_stat)) { case SQLITE_ROW: { - st = sqlite3_column_int(stmt, 0); - goto st_answer; - st_answer: - snprintf(msg_stat, 32, "我已经卖了 %d 句菜", st); - results[0].title = "卖菜统计"; - results[0].text = msg_stat; - results[0].description = "点击发送卖菜统计"; - snprintf(results[0].id, 32, "s%lld", update->sender_user_id_); + personal_stat = sqlite3_column_int(stmt_personal_stat, 0); break; } case SQLITE_DONE: { - st = 0; - goto st_answer; + break; } default: { goto sql_err; } } - sqlite3_finalize(stmt); - stmt = NULL; - - if ((r = sqlite3_prepare_v2(db, - query ? "SELECT id, t, url FROM says WHERE t LIKE ? LIMIT 10;" - : "SELECT id, t, url FROM says ORDER BY RANDOM() LIMIT 10;", - -1, - &stmt, - NULL))) { - goto sql_err; - } + snprintf(msg_stat, sizeof(msg_stat), "我已经卖了 %d 句菜", personal_stat); + snprintf(id_temp, sizeof(id_temp), "s%lld", update->sender_user_id_); + results_inline[0] = create_inline_result(id_temp, "卖菜统计", "点击发送卖菜统计", msg_stat); + effective_items_count ++; - char *query_str = NULL; if (query) { const size_t raw_query_len = strlen(update->query_); if (!(query_str = calloc(raw_query_len + 3, sizeof(char)))) { r = errno; LOGEV("Cannot allocate memory: %s.", strerror(r)); - sqlite3_finalize(stmt); return r; } sprintf(query_str, "%%%s%%", update->query_); - if ((r = sqlite3_bind_text(stmt, 1, query_str, ((int) raw_query_len + 3), NULL))) { - free(query_str); + if ((r = sqlite3_bind_text(stmt_search, 1, query_str, ((int) raw_query_len + 3), NULL))) { goto sql_err; } } - int j = 1; - goto step; - step: - switch (r = sqlite3_step(stmt)) { - case SQLITE_ROW: { - char *t = (char *) sqlite3_column_text(stmt, 1); - char *url = (char *) sqlite3_column_text(stmt, 2); - - char *url1 = NULL; - char *title = NULL; - char *t1 = NULL; - - if (url && !(url1 = strdup(url))) { - LOGEV("Cannot allocate memory: %s.", strerror(errno)); - break; - } - if (!(title = strdup(t))) { - LOGEV("Cannot allocate memory: %s.", strerror(errno)); - break; - } - if (!(t1 = strdup(t))) { - LOGEV("Cannot allocate memory: %s.", strerror(errno)); - break; - } - results[j].title = title; - snprintf(results[j].id, 32, "x_%d", sqlite3_column_int(stmt, 0)); - results[j].text = t1; - results[j].url = url1; - results[j].description = url1; - if ((++j) > 10) break; - goto step; - } - case SQLITE_DONE: { + for (; effective_items_count < sizeof(results_inline) / sizeof(struct TdInputInlineQueryResultArticle *); + effective_items_count ++) { + r = sqlite3_step(stmt_query); + if (r == SQLITE_DONE) { break; } - default: { + if (r != SQLITE_ROW) { goto sql_err; } - } - if (query_str) free(query_str); - sqlite3_finalize(stmt); + int id = sqlite3_column_int(stmt_query, 0); + char *t = (char *) sqlite3_column_text(stmt_query, 1); + char *url = (char *) sqlite3_column_text(stmt_query, 2); - /* There must be a stat option. */ - assert(results[0].title); - goto answer; - answer: - { - struct TdInputInlineQueryResultArticle *results_inline[11]; /* No need to memset(). Var 'i' will assure that. */ - int i; - for (i = 0; i < sizeof(results) / sizeof(struct result); i++) { - struct result res = results[i]; - if (!res.title) { - break; - } - results_inline[i] = TdCreateObjectInputInlineQueryResultArticle( - res.id, - NULL, - false, - res.title, - res.description, - NULL, - 0, - 0, - NULL, - (struct TdInputMessageContent *) TdCreateObjectInputMessageText( - TdCreateObjectFormattedText(res.text, - (struct TdVectorTextEntity *) TdCreateObjectVectorObject(0, - NULL)), - true, - false - )); - } - td_send(TdCreateObjectAnswerInlineQuery(update->id_, - false, - (struct TdVectorInputInlineQueryResult *) - TdCreateObjectVectorObject(i, - (struct TdObject **) results_inline), - 0, - NULL, - NULL, - NULL), - &cb_answer, - NULL); - for (i = 1 /* 0 is error message or stats */; - i < sizeof(results) / sizeof(struct result); i++) { - struct result res = results[i]; - if (!res.title) { - break; - } - free(res.title); - if (res.url) free(res.url); - free(res.text); - } - return r; + snprintf(id_temp, 32, "x_%d", id); + results_inline[effective_items_count] = + create_inline_result(id_temp, + t, + url, + t); } + + td_send(TdCreateObjectAnswerInlineQuery(update->id_, + false, + (struct TdVectorInputInlineQueryResult *) + TdCreateObjectVectorObject(effective_items_count, + (struct TdObject **) results_inline), + 0, + NULL, + NULL, + NULL), + &cb_answer, + NULL); + + goto cleanup; + cleanup: + if (query_str) free(query_str); + sqlite3_reset(stmt_personal_stat); + sqlite3_reset(stmt_query); + return r; } int handle_inline_chosen(struct TdUpdateNewChosenInlineResult *update) { if (!update->result_id_ || update->result_id_[0] != 'x' || - update->result_id_[1] != '_') return 0; + update->result_id_[1] != '_') + return 0; int r; sqlite3_stmt *stmt = NULL; if ((r = sqlite3_prepare_v2(db, "UPDATE stats SET i = i + 1 WHERE user = ?;", -1, &stmt, NULL))) { |