fix(greenplum): drop ctid from table-data SELECT and friendly-fail PK-less edits
Browsing any GP table threw "column ctid does not exist" because the table-viewer's pagination query unconditionally appended `ctid::text` to the SELECT. AO and AOCO tables (the dominant storage in GP) genuinely have no ctid, and even on heap tables the value isn't reliable across segments — so editing by ctid would be wrong even when the column exists. - get_table_data: skip the ctid column entirely on Greenplum (`SELECT *` instead of `SELECT *, ctid::text`); ctids field stays as an empty Vec. - update_row / delete_rows: when the table has no PK on a GP connection, return an actionable error instead of falling through to the ctid path. Tells the user to add a PK or use raw SQL. Vanilla Postgres behavior is unchanged.
This commit is contained in:
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user