Skip to content

Commit 5e4a938

Browse files
committed
Quoting and memory issues fixed
Several quoting issues fixed. Added pfree(elems) and pfree(nulls) after the loop to free memory allocated by deconstruct_array. Moved CStringGetTextDatum allocations before PG_TRY and pfree calls after PG_END_TRY. A need_schema_param flag determines whether 1 or 2 Datums are allocated/freed. This ensures the Datum memory is cleaned up on both the success path and the PG_CATCH error path.
1 parent 6dc7f92 commit 5e4a938

2 files changed

Lines changed: 67 additions & 27 deletions

File tree

src/postgresql/database_postgresql.c

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -314,55 +314,70 @@ char *database_build_base_ref (const char *schema, const char *table_name) {
314314
// Schema parameter: pass empty string to fall back to current_schema() via SQL.
315315
char *sql_build_delete_cols_not_in_schema_query (const char *schema, const char *table_name, const char *meta_ref, const char *pkcol) {
316316
const char *schema_param = schema ? schema : "";
317+
318+
char esc_table[1024], esc_schema[1024];
319+
sql_escape_literal(table_name, esc_table, sizeof(esc_table));
320+
sql_escape_literal(schema_param, esc_schema, sizeof(esc_schema));
321+
317322
return cloudsync_memory_mprintf(
318323
"DELETE FROM %s WHERE col_name NOT IN ("
319324
"SELECT column_name FROM information_schema.columns WHERE table_name = '%s' "
320325
"AND table_schema = COALESCE(NULLIF('%s', ''), current_schema()) "
321326
"UNION SELECT '%s'"
322327
");",
323-
meta_ref, table_name, schema_param, pkcol
328+
meta_ref, esc_table, esc_schema, pkcol
324329
);
325330
}
326331

327332
// Builds query to get comma-separated list of primary key column names.
328333
char *sql_build_pk_collist_query (const char *schema, const char *table_name) {
329334
const char *schema_param = schema ? schema : "";
335+
336+
char esc_table[1024], esc_schema[1024];
337+
sql_escape_literal(table_name, esc_table, sizeof(esc_table));
338+
sql_escape_literal(schema_param, esc_schema, sizeof(esc_schema));
339+
330340
return cloudsync_memory_mprintf(
331341
"SELECT string_agg(quote_ident(column_name), ',') "
332342
"FROM information_schema.key_column_usage "
333343
"WHERE table_name = '%s' AND table_schema = COALESCE(NULLIF('%s', ''), current_schema()) "
334344
"AND constraint_name LIKE '%%_pkey';",
335-
table_name, schema_param
345+
esc_table, esc_schema
336346
);
337347
}
338348

339349
// Builds query to get SELECT list of decoded primary key columns.
340350
char *sql_build_pk_decode_selectlist_query (const char *schema, const char *table_name) {
341351
const char *schema_param = schema ? schema : "";
352+
353+
char esc_table[1024], esc_schema[1024];
354+
sql_escape_literal(table_name, esc_table, sizeof(esc_table));
355+
sql_escape_literal(schema_param, esc_schema, sizeof(esc_schema));
356+
342357
return cloudsync_memory_mprintf(
343358
"SELECT string_agg("
344359
"'cloudsync_pk_decode(pk, ' || ordinal_position || ') AS ' || quote_ident(column_name), ',' ORDER BY ordinal_position"
345360
") "
346361
"FROM information_schema.key_column_usage "
347362
"WHERE table_name = '%s' AND table_schema = COALESCE(NULLIF('%s', ''), current_schema()) "
348363
"AND constraint_name LIKE '%%_pkey';",
349-
table_name, schema_param
364+
esc_table, esc_schema
350365
);
351366
}
352367

353368
// Builds query to get qualified (schema.table.column) primary key column list.
354369
char *sql_build_pk_qualified_collist_query (const char *schema, const char *table_name) {
355370
const char *schema_param = schema ? schema : "";
356-
357-
char buffer[1024];
358-
char *singlequote_escaped_table_name = sql_escape_literal(table_name, buffer, sizeof(buffer));
359-
if (!singlequote_escaped_table_name) return NULL;
360-
371+
372+
char esc_table[1024], esc_schema[1024];
373+
sql_escape_literal(table_name, esc_table, sizeof(esc_table));
374+
sql_escape_literal(schema_param, esc_schema, sizeof(esc_schema));
375+
361376
return cloudsync_memory_mprintf(
362377
"SELECT string_agg(quote_ident(column_name), ',' ORDER BY ordinal_position) "
363378
"FROM information_schema.key_column_usage "
364379
"WHERE table_name = '%s' AND table_schema = COALESCE(NULLIF('%s', ''), current_schema()) "
365-
"AND constraint_name LIKE '%%_pkey';", singlequote_escaped_table_name, schema_param
380+
"AND constraint_name LIKE '%%_pkey';", esc_table, esc_schema
366381
);
367382
}
368383

@@ -645,28 +660,29 @@ static bool database_system_exists (cloudsync_context *data, const char *name, c
645660
return false;
646661
}
647662

663+
bool need_schema_param = !force_public && strcmp(type, "trigger") != 0;
664+
Datum datum_name = CStringGetTextDatum(name);
665+
Datum datum_schema = need_schema_param ? CStringGetTextDatum(schema_param) : (Datum)0;
666+
648667
MemoryContext oldcontext = CurrentMemoryContext;
649668
PG_TRY();
650669
{
651-
if (force_public || strcmp(type, "trigger") == 0) {
670+
if (!need_schema_param) {
652671
// force_public or trigger: only need table/trigger name parameter
653672
Oid argtypes[1] = {TEXTOID};
654-
Datum values[1] = {CStringGetTextDatum(name)};
673+
Datum values[1] = {datum_name};
655674
char nulls[1] = {' '};
656675
int rc = SPI_execute_with_args(query, 1, argtypes, values, nulls, true, 0);
657676
exists = (rc >= 0 && SPI_processed > 0);
658677
if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
659-
pfree(DatumGetPointer(values[0]));
660678
} else {
661679
// table with schema parameter
662680
Oid argtypes[2] = {TEXTOID, TEXTOID};
663-
Datum values[2] = {CStringGetTextDatum(name), CStringGetTextDatum(schema_param)};
681+
Datum values[2] = {datum_name, datum_schema};
664682
char nulls[2] = {' ', ' '};
665683
int rc = SPI_execute_with_args(query, 2, argtypes, values, nulls, true, 0);
666684
exists = (rc >= 0 && SPI_processed > 0);
667685
if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
668-
pfree(DatumGetPointer(values[0]));
669-
pfree(DatumGetPointer(values[1]));
670686
}
671687
}
672688
PG_CATCH();
@@ -680,6 +696,9 @@ static bool database_system_exists (cloudsync_context *data, const char *name, c
680696
}
681697
PG_END_TRY();
682698

699+
pfree(DatumGetPointer(datum_name));
700+
if (need_schema_param) pfree(DatumGetPointer(datum_schema));
701+
683702
elog(DEBUG1, "database_system_exists %s: %d", name, exists);
684703
return exists;
685704
}
@@ -1135,6 +1154,10 @@ static int database_create_insert_trigger_internal (cloudsync_context *data, con
11351154

11361155
if (database_trigger_exists(data, trigger_name)) return DBRES_OK;
11371156

1157+
char esc_tbl_literal[1024], esc_schema_literal[1024];
1158+
sql_escape_literal(table_name, esc_tbl_literal, sizeof(esc_tbl_literal));
1159+
sql_escape_literal(schema_param, esc_schema_literal, sizeof(esc_schema_literal));
1160+
11381161
char sql[2048];
11391162
snprintf(sql, sizeof(sql),
11401163
"SELECT string_agg('NEW.' || quote_ident(kcu.column_name), ',' ORDER BY kcu.ordinal_position) "
@@ -1144,7 +1167,7 @@ static int database_create_insert_trigger_internal (cloudsync_context *data, con
11441167
" AND tc.table_schema = kcu.table_schema "
11451168
"WHERE tc.table_name = '%s' AND tc.table_schema = COALESCE(NULLIF('%s', ''), current_schema()) "
11461169
"AND tc.constraint_type = 'PRIMARY KEY';",
1147-
table_name, schema_param);
1170+
esc_tbl_literal, esc_schema_literal);
11481171

11491172
char *pk_list = NULL;
11501173
int rc = database_select_text(data, sql, &pk_list);
@@ -1162,7 +1185,7 @@ static int database_create_insert_trigger_internal (cloudsync_context *data, con
11621185
" RETURN NEW; "
11631186
"END; "
11641187
"$$ LANGUAGE plpgsql;",
1165-
func_name, table_name, table_name, pk_list);
1188+
func_name, esc_tbl_literal, esc_tbl_literal, pk_list);
11661189
cloudsync_memory_free(pk_list);
11671190
if (!sql2) return DBRES_NOMEM;
11681191

@@ -1197,13 +1220,16 @@ static int database_create_update_trigger_gos_internal (cloudsync_context *data,
11971220

11981221
if (database_trigger_exists(data, trigger_name)) return DBRES_OK;
11991222

1223+
char esc_tbl_literal[1024];
1224+
sql_escape_literal(table_name, esc_tbl_literal, sizeof(esc_tbl_literal));
1225+
12001226
char *sql = cloudsync_memory_mprintf(
12011227
"CREATE OR REPLACE FUNCTION \"%s\"() RETURNS trigger AS $$ "
12021228
"BEGIN "
12031229
" RAISE EXCEPTION 'Error: UPDATE operation is not allowed on table %s.'; "
12041230
"END; "
12051231
"$$ LANGUAGE plpgsql;",
1206-
func_name, table_name);
1232+
func_name, esc_tbl_literal);
12071233
if (!sql) return DBRES_NOMEM;
12081234

12091235
int rc = database_exec(data, sql);
@@ -1217,7 +1243,7 @@ static int database_create_update_trigger_gos_internal (cloudsync_context *data,
12171243
"CREATE TRIGGER \"%s\" BEFORE UPDATE ON %s "
12181244
"FOR EACH ROW WHEN (cloudsync_is_enabled('%s') = true) "
12191245
"EXECUTE FUNCTION \"%s\"();",
1220-
trigger_name, base_ref, table_name, func_name);
1246+
trigger_name, base_ref, esc_tbl_literal, func_name);
12211247
cloudsync_memory_free(base_ref);
12221248
if (!sql) return DBRES_NOMEM;
12231249

@@ -1240,6 +1266,10 @@ static int database_create_update_trigger_internal (cloudsync_context *data, con
12401266

12411267
if (database_trigger_exists(data, trigger_name)) return DBRES_OK;
12421268

1269+
char esc_tbl_literal[1024], esc_schema_literal[1024];
1270+
sql_escape_literal(table_name, esc_tbl_literal, sizeof(esc_tbl_literal));
1271+
sql_escape_literal(schema_param, esc_schema_literal, sizeof(esc_schema_literal));
1272+
12431273
char sql[2048];
12441274
snprintf(sql, sizeof(sql),
12451275
"SELECT string_agg("
@@ -1253,7 +1283,7 @@ static int database_create_update_trigger_internal (cloudsync_context *data, con
12531283
" AND tc.table_schema = kcu.table_schema "
12541284
"WHERE tc.table_name = '%s' AND tc.table_schema = COALESCE(NULLIF('%s', ''), current_schema()) "
12551285
"AND tc.constraint_type = 'PRIMARY KEY';",
1256-
table_name, table_name, schema_param);
1286+
esc_tbl_literal, esc_tbl_literal, esc_schema_literal);
12571287

12581288
char *pk_values_list = NULL;
12591289
int rc = database_select_text(data, sql, &pk_values_list);
@@ -1282,7 +1312,7 @@ static int database_create_update_trigger_internal (cloudsync_context *data, con
12821312
" AND tc.constraint_type = 'PRIMARY KEY' "
12831313
" AND kcu.column_name = c.column_name"
12841314
");",
1285-
table_name, table_name, schema_param);
1315+
esc_tbl_literal, esc_tbl_literal, esc_schema_literal);
12861316

12871317
char *col_values_list = NULL;
12881318
rc = database_select_text(data, sql, &col_values_list);
@@ -1311,7 +1341,7 @@ static int database_create_update_trigger_internal (cloudsync_context *data, con
13111341
" RETURN NEW; "
13121342
"END; "
13131343
"$$ LANGUAGE plpgsql;",
1314-
func_name, table_name, values_query);
1344+
func_name, esc_tbl_literal, values_query);
13151345
cloudsync_memory_free(values_query);
13161346
if (!sql2) return DBRES_NOMEM;
13171347

@@ -1346,13 +1376,16 @@ static int database_create_delete_trigger_gos_internal (cloudsync_context *data,
13461376

13471377
if (database_trigger_exists(data, trigger_name)) return DBRES_OK;
13481378

1379+
char esc_tbl_literal[1024];
1380+
sql_escape_literal(table_name, esc_tbl_literal, sizeof(esc_tbl_literal));
1381+
13491382
char *sql = cloudsync_memory_mprintf(
13501383
"CREATE OR REPLACE FUNCTION \"%s\"() RETURNS trigger AS $$ "
13511384
"BEGIN "
13521385
" RAISE EXCEPTION 'Error: DELETE operation is not allowed on table %s.'; "
13531386
"END; "
13541387
"$$ LANGUAGE plpgsql;",
1355-
func_name, table_name);
1388+
func_name, esc_tbl_literal);
13561389
if (!sql) return DBRES_NOMEM;
13571390

13581391
int rc = database_exec(data, sql);
@@ -1366,7 +1399,7 @@ static int database_create_delete_trigger_gos_internal (cloudsync_context *data,
13661399
"CREATE TRIGGER \"%s\" BEFORE DELETE ON %s "
13671400
"FOR EACH ROW WHEN (cloudsync_is_enabled('%s') = true) "
13681401
"EXECUTE FUNCTION \"%s\"();",
1369-
trigger_name, base_ref, table_name, func_name);
1402+
trigger_name, base_ref, esc_tbl_literal, func_name);
13701403
cloudsync_memory_free(base_ref);
13711404
if (!sql) return DBRES_NOMEM;
13721405

@@ -1389,6 +1422,10 @@ static int database_create_delete_trigger_internal (cloudsync_context *data, con
13891422

13901423
if (database_trigger_exists(data, trigger_name)) return DBRES_OK;
13911424

1425+
char esc_tbl_literal[1024], esc_schema_literal[1024];
1426+
sql_escape_literal(table_name, esc_tbl_literal, sizeof(esc_tbl_literal));
1427+
sql_escape_literal(schema_param, esc_schema_literal, sizeof(esc_schema_literal));
1428+
13921429
char sql[2048];
13931430
snprintf(sql, sizeof(sql),
13941431
"SELECT string_agg('OLD.' || quote_ident(kcu.column_name), ',' ORDER BY kcu.ordinal_position) "
@@ -1398,7 +1435,7 @@ static int database_create_delete_trigger_internal (cloudsync_context *data, con
13981435
" AND tc.table_schema = kcu.table_schema "
13991436
"WHERE tc.table_name = '%s' AND tc.table_schema = COALESCE(NULLIF('%s', ''), current_schema()) "
14001437
"AND tc.constraint_type = 'PRIMARY KEY';",
1401-
table_name, schema_param);
1438+
esc_tbl_literal, esc_schema_literal);
14021439

14031440
char *pk_list = NULL;
14041441
int rc = database_select_text(data, sql, &pk_list);
@@ -1416,15 +1453,15 @@ static int database_create_delete_trigger_internal (cloudsync_context *data, con
14161453
" RETURN OLD; "
14171454
"END; "
14181455
"$$ LANGUAGE plpgsql;",
1419-
func_name, table_name, table_name, pk_list);
1456+
func_name, esc_tbl_literal, esc_tbl_literal, pk_list);
14201457
cloudsync_memory_free(pk_list);
14211458
if (!sql2) return DBRES_NOMEM;
14221459

14231460
rc = database_exec(data, sql2);
14241461
cloudsync_memory_free(sql2);
14251462
if (rc != DBRES_OK) return rc;
14261463

1427-
char *base_ref = database_build_base_ref(cloudsync_schema(data), table_name);
1464+
char *base_ref = database_build_base_ref(schema, table_name);
14281465
if (!base_ref) return DBRES_NOMEM;
14291466

14301467
sql2 = cloudsync_memory_mprintf(

src/postgresql/pgvalue.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ pgvalue_t **pgvalues_from_array(ArrayType *array, int *out_count) {
125125
pgvalue_vec_push(&values, &count, &cap, v);
126126
}
127127

128+
if (elems) pfree(elems);
129+
if (nulls) pfree(nulls);
130+
128131
if (out_count) *out_count = count;
129132
return values;
130133
}

0 commit comments

Comments
 (0)