]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-sql: Use strchr() based while loop to fill template
authorAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 18 Aug 2025 05:30:42 +0000 (08:30 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 18 Aug 2025 05:30:42 +0000 (08:30 +0300)
This is much faster than going one byte at a time.

src/lib-sql/sql-api.c
src/lib-sql/test-sql.c

index 1bdc5599e5b8173e51a01cbe9f50767c0a1dd369..148ff84dd61e999cd87fb71465346b69ca781e85 100644 (file)
@@ -292,22 +292,24 @@ const char *sql_statement_get_query(struct sql_statement *stmt)
 {
        string_t *query = t_str_new(128);
        const char *const *args;
-       unsigned int i, args_count, arg_pos = 0;
+       unsigned int args_count, arg_pos = 0;
+       const char *p0, *p1;
 
        args = array_get(&stmt->args, &args_count);
-
-       for (i = 0; stmt->query_template[i] != '\0'; i++) {
-               if (stmt->query_template[i] == '?') {
-                       if (arg_pos >= args_count ||
-                           args[arg_pos] == NULL) {
-                               i_panic("lib-sql: Missing bind for arg #%u in statement: %s",
-                                       arg_pos, stmt->query_template);
-                       }
-                       str_append(query, args[arg_pos++]);
-               } else {
-                       str_append_c(query, stmt->query_template[i]);
+       p0 = stmt->query_template;
+       while ((p1 = strchr(p0, '?')) != NULL) {
+               /* append until ? */
+               str_append_max(query, p0, (p1 - p0));
+               if (arg_pos >= args_count ||
+                   args[arg_pos] == NULL) {
+                       i_panic("lib-sql: Missing bind for arg #%u in statement: %s",
+                               arg_pos, stmt->query_template);
                }
+               str_append(query, args[arg_pos++]);
+               p0 = p1 + 1;
        }
+       str_append(query, p0);
+
        if (arg_pos != args_count) {
                i_panic("lib-sql: Too many bind args (%u) for statement: %s",
                        args_count, stmt->query_template);
index f4a432efcdbe2c84caabbc03b389f1351b165eed..3945268e403de83ca9d209545756897041f1c4fd 100644 (file)
@@ -60,6 +60,24 @@ static void deinit_sql(struct sql_db **_sql)
        }; \
        sql_driver_test_add_expected_result(sql, &result_1);
 
+#define setup_result_2(sql) \
+       struct test_driver_result_set rset_2 = { \
+               .rows = 2, \
+               .cols = 1, \
+               .col_names = (const char *[]){"foo", NULL}, \
+               .row_data = (const char **[]){ \
+                       (const char*[]){"value1", NULL}, \
+                       (const char*[]){"value2", NULL}, \
+               }, \
+       }; \
+       struct test_driver_result result_2 = { \
+               .nqueries = 1, \
+               .queries = (const char *[]){"SELECT foo FROM bar WHERE baz = 'foz'"}, \
+               .result = &rset_2 \
+       }; \
+       sql_driver_test_add_expected_result(sql, &result_2);
+
+
 static void test_result_1(struct sql_result *cursor)
 {
        test_assert(sql_result_next_row(cursor) == SQL_RESULT_NEXT_OK);
@@ -127,6 +145,18 @@ static void test_sql_stmt_prepared_api(void)
 
        sql_result_unref(cursor);
 
+       setup_result_2(sql);
+
+       prep_stmt = sql_prepared_statement_init(sql, "SELECT foo FROM bar WHERE baz = ?");
+       stmt = sql_statement_init_prepared(prep_stmt);
+       sql_statement_bind_str(stmt, 0, "foz");
+       sql_prepared_statement_unref(&prep_stmt);
+       cursor = sql_statement_query_s(&stmt);
+
+       test_result_1(cursor);
+
+       sql_result_unref(cursor);
+
        deinit_sql(&sql);
        test_end();
 }