Skip to content

Commit 360a057

Browse files
committed
fix: fix internal queries to support table/column names with single quotes or double quotes
1 parent cbddca0 commit 360a057

File tree

5 files changed

+226
-160
lines changed

5 files changed

+226
-160
lines changed

src/cloudsync.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ char *db_version_build_query (sqlite3 *db) {
360360

361361
// the good news is that the query can be computed in SQLite without the need to do any extra computation from the host language
362362
const char *sql = "WITH table_names AS ("
363-
"SELECT format('%q', name) as tbl_name "
363+
"SELECT format('%w', name) as tbl_name "
364364
"FROM sqlite_master "
365365
"WHERE type='table' "
366366
"AND name LIKE '%_cloudsync'"
@@ -504,19 +504,22 @@ char *table_build_values_sql (sqlite3 *db, cloudsync_table_context *table) {
504504

505505
// Unfortunately in SQLite column names (or table names) cannot be bound parameters in a SELECT statement
506506
// otherwise we should have used something like SELECT 'SELECT ? FROM %w WHERE rowid=?';
507-
507+
508+
char *singlequote_escaped_table_name = cloudsync_memory_mprintf("%q", table->name);
509+
508510
#if !CLOUDSYNC_DISABLE_ROWIDONLY_TABLES
509511
if (table->rowid_only) {
510-
sql = memory_mprintf("WITH col_names AS (SELECT group_concat('\"' || name || '\"', ',') AS cols FROM pragma_table_info('%q') WHERE pk=0 ORDER BY cid) SELECT 'SELECT ' || (SELECT cols FROM col_names) || ' FROM \"%w\" WHERE rowid=?;'", table->name, table->name);
512+
sql = memory_mprintf("WITH col_names AS (SELECT group_concat('\"' || format('%%w', name) || '\"', ',') AS cols FROM pragma_table_info('%q') WHERE pk=0 ORDER BY cid) SELECT 'SELECT ' || (SELECT cols FROM col_names) || ' FROM \"%w\" WHERE rowid=?;'", table->name, table->name);
511513
goto process_process;
512514
}
513515
#endif
514516

515-
sql = cloudsync_memory_mprintf("WITH col_names AS (SELECT group_concat('\"' || name || '\"', ',') AS cols FROM pragma_table_info('%q') WHERE pk=0 ORDER BY cid), pk_where AS (SELECT group_concat('\"' || name || '\"', '=? AND ') || '=?' AS pk_clause FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk) SELECT 'SELECT ' || (SELECT cols FROM col_names) || ' FROM \"%w\" WHERE ' || (SELECT pk_clause FROM pk_where) || ';'", table->name, table->name, table->name);
516-
517+
sql = cloudsync_memory_mprintf("WITH col_names AS (SELECT group_concat('\"' || format('%%w', name) || '\"', ',') AS cols FROM pragma_table_info('%q') WHERE pk=0 ORDER BY cid), pk_where AS (SELECT group_concat('\"' || format('%%w', name) || '\"', '=? AND ') || '=?' AS pk_clause FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk) SELECT 'SELECT ' || (SELECT cols FROM col_names) || ' FROM \"%w\" WHERE ' || (SELECT pk_clause FROM pk_where) || ';'", table->name, table->name, singlequote_escaped_table_name);
518+
517519
#if !CLOUDSYNC_DISABLE_ROWIDONLY_TABLES
518520
process_process:
519521
#endif
522+
cloudsync_memory_free(singlequote_escaped_table_name);
520523
if (!sql) return NULL;
521524
char *query = dbutils_text_select(db, sql);
522525
cloudsync_memory_free(sql);
@@ -532,7 +535,9 @@ char *table_build_mergedelete_sql (sqlite3 *db, cloudsync_table_context *table)
532535
}
533536
#endif
534537

535-
char *sql = cloudsync_memory_mprintf("WITH pk_where AS (SELECT group_concat('\"' || name || '\"', '=? AND ') || '=?' AS pk_clause FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk) SELECT 'DELETE FROM \"%w\" WHERE ' || (SELECT pk_clause FROM pk_where) || ';'", table->name, table->name);
538+
char *singlequote_escaped_table_name = cloudsync_memory_mprintf("%q", table->name);
539+
char *sql = cloudsync_memory_mprintf("WITH pk_where AS (SELECT group_concat('\"' || format('%%w', name) || '\"', '=? AND ') || '=?' AS pk_clause FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk) SELECT 'DELETE FROM \"%w\" WHERE ' || (SELECT pk_clause FROM pk_where) || ';'", table->name, singlequote_escaped_table_name);
540+
cloudsync_memory_free(singlequote_escaped_table_name);
536541
if (!sql) return NULL;
537542

538543
char *query = dbutils_text_select(db, sql);
@@ -557,12 +562,18 @@ char *table_build_mergeinsert_sql (sqlite3 *db, cloudsync_table_context *table,
557562
}
558563
#endif
559564

565+
char *singlequote_escaped_table_name = cloudsync_memory_mprintf("%q", table->name);
566+
560567
if (colname == NULL) {
561568
// is sentinel insert
562-
sql = cloudsync_memory_mprintf("WITH pk_where AS (SELECT group_concat('\"' || name || '\"') AS pk_clause FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk), pk_bind AS (SELECT group_concat('?') AS pk_binding FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk) SELECT 'INSERT OR IGNORE INTO \"%w\" (' || (SELECT pk_clause FROM pk_where) || ') VALUES (' || (SELECT pk_binding FROM pk_bind) || ');'", table->name, table->name, table->name);
569+
sql = cloudsync_memory_mprintf("WITH pk_where AS (SELECT group_concat('\"' || format('%%w', name) || '\"') AS pk_clause FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk), pk_bind AS (SELECT group_concat('?') AS pk_binding FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk) SELECT 'INSERT OR IGNORE INTO \"%w\" (' || (SELECT pk_clause FROM pk_where) || ') VALUES (' || (SELECT pk_binding FROM pk_bind) || ');'", table->name, table->name, singlequote_escaped_table_name);
563570
} else {
564-
sql = cloudsync_memory_mprintf("WITH pk_where AS (SELECT group_concat('\"' || name || '\"') AS pk_clause FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk), pk_bind AS (SELECT group_concat('?') AS pk_binding FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk) SELECT 'INSERT INTO \"%w\" (' || (SELECT pk_clause FROM pk_where) || ',\"%w\") VALUES (' || (SELECT pk_binding FROM pk_bind) || ',?) ON CONFLICT DO UPDATE SET \"%w\"=?;'", table->name, table->name, table->name, colname, colname);
571+
char *singlequote_escaped_col_name = cloudsync_memory_mprintf("%q", colname);
572+
sql = cloudsync_memory_mprintf("WITH pk_where AS (SELECT group_concat('\"' || format('%%w', name) || '\"') AS pk_clause FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk), pk_bind AS (SELECT group_concat('?') AS pk_binding FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk) SELECT 'INSERT INTO \"%w\" (' || (SELECT pk_clause FROM pk_where) || ',\"%w\") VALUES (' || (SELECT pk_binding FROM pk_bind) || ',?) ON CONFLICT DO UPDATE SET \"%w\"=?;'", table->name, table->name, singlequote_escaped_table_name, singlequote_escaped_col_name, singlequote_escaped_col_name);
573+
cloudsync_memory_free(singlequote_escaped_col_name);
574+
565575
}
576+
cloudsync_memory_free(singlequote_escaped_table_name);
566577
if (!sql) return NULL;
567578

568579
char *query = dbutils_text_select(db, sql);
@@ -582,7 +593,11 @@ char *table_build_value_sql (sqlite3 *db, cloudsync_table_context *table, const
582593
#endif
583594

584595
// SELECT age FROM customers WHERE first_name=? AND last_name=?;
585-
char *sql = cloudsync_memory_mprintf("WITH pk_where AS (SELECT group_concat('\"' || name || '\"', '=? AND ') || '=?' AS pk_clause FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk) SELECT 'SELECT %s%w%s FROM \"%w\" WHERE ' || (SELECT pk_clause FROM pk_where) || ';'", table->name, colnamequote, colname, colnamequote, table->name);
596+
char *singlequote_escaped_table_name = cloudsync_memory_mprintf("%q", table->name);
597+
char *singlequote_escaped_col_name = cloudsync_memory_mprintf("%q", colname);
598+
char *sql = cloudsync_memory_mprintf("WITH pk_where AS (SELECT group_concat('\"' || format('%%w', name) || '\"', '=? AND ') || '=?' AS pk_clause FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk) SELECT 'SELECT %s%w%s FROM \"%w\" WHERE ' || (SELECT pk_clause FROM pk_where) || ';'", table->name, colnamequote, singlequote_escaped_col_name, colnamequote, singlequote_escaped_table_name);
599+
cloudsync_memory_free(singlequote_escaped_col_name);
600+
cloudsync_memory_free(singlequote_escaped_table_name);
586601
if (!sql) return NULL;
587602

588603
char *query = dbutils_text_select(db, sql);
@@ -1638,7 +1653,9 @@ int cloudsync_finalize_alter (sqlite3_context *context, cloudsync_context *data,
16381653
goto finalize;
16391654
}
16401655

1641-
sql = cloudsync_memory_mprintf("SELECT group_concat('\"%w\".\"' || name || '\"', ',') FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk;", table->name, table->name);
1656+
char *singlequote_escaped_table_name = cloudsync_memory_mprintf("%q", table->name);
1657+
sql = cloudsync_memory_mprintf("SELECT group_concat('\"%w\".\"' || format('%%w', name) || '\"', ',') FROM pragma_table_info('%s') WHERE pk>0 ORDER BY pk;", singlequote_escaped_table_name, singlequote_escaped_table_name);
1658+
cloudsync_memory_free(singlequote_escaped_table_name);
16421659
if (!sql) {
16431660
rc = SQLITE_NOMEM;
16441661
goto finalize;
@@ -1677,17 +1694,17 @@ int cloudsync_refill_metatable (sqlite3 *db, cloudsync_context *data, const char
16771694
sqlite3_stmt *vm = NULL;
16781695
sqlite3_int64 db_version = db_version_next(db, data, CLOUDSYNC_VALUE_NOTSET);
16791696

1680-
char *sql = cloudsync_memory_mprintf("SELECT group_concat('\"' || name || '\"', ',') FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk;", table_name);
1697+
char *sql = cloudsync_memory_mprintf("SELECT group_concat('\"' || format('%%w', name) || '\"', ',') FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk;", table_name);
16811698
char *pkclause_identifiers = dbutils_text_select(db, sql);
16821699
char *pkvalues_identifiers = (pkclause_identifiers) ? pkclause_identifiers : "rowid";
16831700
cloudsync_memory_free(sql);
16841701

1685-
sql = cloudsync_memory_mprintf("SELECT group_concat('cloudsync_pk_decode(pk, ' || pk || ') AS ' || '\"' || name || '\"', ',') FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk;", table_name);
1702+
sql = cloudsync_memory_mprintf("SELECT group_concat('cloudsync_pk_decode(pk, ' || pk || ') AS ' || '\"' || format('%%w', name) || '\"', ',') FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk;", table_name);
16861703
char *pkdecode = dbutils_text_select(db, sql);
16871704
char *pkdecodeval = (pkdecode) ? pkdecode : "cloudsync_pk_decode(pk, 1) AS rowid";
16881705
cloudsync_memory_free(sql);
16891706

1690-
sql = cloudsync_memory_mprintf("SELECT group_concat('\"' || name || '\"' || ' = cloudsync_pk_decode(pk, ' || pk || ')', ' AND ') FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk;", table_name);
1707+
sql = cloudsync_memory_mprintf("SELECT group_concat('\"' || format('%%w', name) || '\"' || ' = cloudsync_pk_decode(pk, ' || pk || ')', ' AND ') FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk;", table_name);
16911708
char *pkonclause = dbutils_text_select(db, sql);
16921709
char *pkonclauseval = (pkonclause) ? pkonclause : "rowid = cloudsync_pk_decode(pk, 1) AS rowid";
16931710
cloudsync_memory_free(sql);

src/cloudsync.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "sqlite3.h"
1717
#endif
1818

19-
#define CLOUDSYNC_VERSION "0.8.9"
19+
#define CLOUDSYNC_VERSION "0.8.10"
2020

2121
int sqlite3_cloudsync_init (sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
2222

0 commit comments

Comments
 (0)