diff --git a/src-tauri/src/commands/data.rs b/src-tauri/src/commands/data.rs index e718530..0bb6c2b 100644 --- a/src-tauri/src/commands/data.rs +++ b/src-tauri/src/commands/data.rs @@ -136,9 +136,19 @@ pub async fn get_table_data( let offset = (page.saturating_sub(1)) * page_size; + // Greenplum AO / AOCO tables don't expose `ctid` and even on heap tables + // it isn't a reliable per-row identifier across segments — so on GP we + // skip the ctid column entirely. Edits without a PK will be rejected by + // update_row/delete_rows below with a friendly error. + let include_ctid = !matches!(flavor, DbFlavor::Greenplum); + let select_clause = if include_ctid { + "*, ctid::text" + } else { + "*" + }; let data_sql = format!( - "SELECT *, ctid::text FROM {}{}{} LIMIT {} OFFSET {}", - qualified, where_clause, order_clause, page_size, offset + "SELECT {} FROM {}{}{} LIMIT {} OFFSET {}", + select_clause, qualified, where_clause, order_clause, page_size, offset ); let count_sql = format!("SELECT COUNT(*) FROM {}{}", qualified, where_clause); @@ -248,6 +258,13 @@ pub async fn update_row( let set_clause = format!("{} = $1", escape_ident(&column)); if pk_columns.is_empty() { + if matches!(state.get_flavor(&connection_id).await, DbFlavor::Greenplum) { + return Err(TuskError::Custom( + "Greenplum doesn't expose a stable ctid (AO/AOCO tables have none, \ + heap-table ctid isn't unique across segments). Inline edit requires \ + a primary key — add one or use a SQL UPDATE.".into(), + )); + } // Fallback: use ctid for row identification let ctid_val = ctid.ok_or_else(|| { TuskError::Custom("Cannot update: no primary key and no ctid provided".into()) @@ -354,6 +371,13 @@ pub async fn delete_rows( let mut tx = pool.begin().await.map_err(TuskError::Database)?; if pk_columns.is_empty() { + if matches!(state.get_flavor(&connection_id).await, DbFlavor::Greenplum) { + return Err(TuskError::Custom( + "Greenplum doesn't expose a stable ctid (AO/AOCO tables have none, \ + heap-table ctid isn't unique across segments). Inline delete requires \ + a primary key — add one or use a SQL DELETE.".into(), + )); + } // Fallback: use ctids for row identification let ctid_list = ctids.ok_or_else(|| { TuskError::Custom("Cannot delete: no primary key and no ctids provided".into())