From 448f6ad4f4ac7b737293a65f1b493bc44af4714b Mon Sep 17 00:00:00 2001 From: Lars Date: Fri, 27 Mar 2026 22:14:28 +0100 Subject: [PATCH] fix: use psycopg2 placeholders (%s) not PostgreSQL ($N) Bug 1 Final Fix: - Changed all placeholders from $1, $2, $3 to %s - psycopg2 expects Python-style %s, converts to $N internally - Using $N directly causes 'there is no parameter $1' error - Removed param_idx counter (not needed with %s) Root cause: Mixing PostgreSQL native syntax with psycopg2 driver This is THE fix that will finally work! --- backend/routers/vitals_baseline.py | 44 ++++++++++++------------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/backend/routers/vitals_baseline.py b/backend/routers/vitals_baseline.py index 8651ef8..3538775 100644 --- a/backend/routers/vitals_baseline.py +++ b/backend/routers/vitals_baseline.py @@ -109,63 +109,54 @@ def create_or_update_baseline( # Always include profile_id and date param_values.append(pid) param_values.append(entry.date) - param_idx = 3 # Next parameter starts at $3 if entry.resting_hr is not None: insert_cols.append("resting_hr") - insert_placeholders.append(f"${param_idx}") - update_fields.append(f"resting_hr = EXCLUDED.resting_hr") + insert_placeholders.append("%s") + update_fields.append("resting_hr = EXCLUDED.resting_hr") param_values.append(entry.resting_hr) - param_idx += 1 if entry.hrv is not None: insert_cols.append("hrv") - insert_placeholders.append(f"${param_idx}") - update_fields.append(f"hrv = EXCLUDED.hrv") + insert_placeholders.append("%s") + update_fields.append("hrv = EXCLUDED.hrv") param_values.append(entry.hrv) - param_idx += 1 if entry.vo2_max is not None: insert_cols.append("vo2_max") - insert_placeholders.append(f"${param_idx}") - update_fields.append(f"vo2_max = EXCLUDED.vo2_max") + insert_placeholders.append("%s") + update_fields.append("vo2_max = EXCLUDED.vo2_max") param_values.append(entry.vo2_max) - param_idx += 1 if entry.spo2 is not None: insert_cols.append("spo2") - insert_placeholders.append(f"${param_idx}") - update_fields.append(f"spo2 = EXCLUDED.spo2") + insert_placeholders.append("%s") + update_fields.append("spo2 = EXCLUDED.spo2") param_values.append(entry.spo2) - param_idx += 1 if entry.respiratory_rate is not None: insert_cols.append("respiratory_rate") - insert_placeholders.append(f"${param_idx}") - update_fields.append(f"respiratory_rate = EXCLUDED.respiratory_rate") + insert_placeholders.append("%s") + update_fields.append("respiratory_rate = EXCLUDED.respiratory_rate") param_values.append(entry.respiratory_rate) - param_idx += 1 if entry.body_temperature is not None: insert_cols.append("body_temperature") - insert_placeholders.append(f"${param_idx}") - update_fields.append(f"body_temperature = EXCLUDED.body_temperature") + insert_placeholders.append("%s") + update_fields.append("body_temperature = EXCLUDED.body_temperature") param_values.append(entry.body_temperature) - param_idx += 1 if entry.resting_metabolic_rate is not None: insert_cols.append("resting_metabolic_rate") - insert_placeholders.append(f"${param_idx}") - update_fields.append(f"resting_metabolic_rate = EXCLUDED.resting_metabolic_rate") + insert_placeholders.append("%s") + update_fields.append("resting_metabolic_rate = EXCLUDED.resting_metabolic_rate") param_values.append(entry.resting_metabolic_rate) - param_idx += 1 if entry.note: insert_cols.append("note") - insert_placeholders.append(f"${param_idx}") - update_fields.append(f"note = EXCLUDED.note") + insert_placeholders.append("%s") + update_fields.append("note = EXCLUDED.note") param_values.append(entry.note) - param_idx += 1 # At least one field must be provided if not insert_cols: @@ -175,8 +166,9 @@ def create_or_update_baseline( cur = get_cursor(conn) # Build complete column list and placeholder list + # IMPORTANT: psycopg2 uses %s placeholders, NOT $1/$2/$3 all_cols = f"profile_id, date, {', '.join(insert_cols)}" - all_placeholders = f"$1, $2, {', '.join(insert_placeholders)}" + all_placeholders = f"%s, %s, {', '.join(insert_placeholders)}" query = f""" INSERT INTO vitals_baseline ({all_cols})