Hi all, I noticed that if you add, delete, rename or change the type, collation or precision of a composite type attribute, it deletes all of them then adds them all back in. Obviously attribute additions, deletions and modifications may only occur for types under PostgreSQL 9.1, but I thought it a bit extreme to actually drop all types if you're adding a new one in, or just removing one. Also, if you rename a type, it drops all attributes again then re-adds them, just to have an attribute with a different name.
So I've attached a patch which "does the right thing". Take the example of the following type: CREATE TYPE bark AS (one text, two text, three text, four text, five text); Say we wanted to remove "two", change the type of three to uuid, rename four to forty and add an extra text type of six. Normally we'd just get: ALTER TYPE bark DROP ATTRIBUTE one; ALTER TYPE bark DROP ATTRIBUTE two; ALTER TYPE bark DROP ATTRIBUTE three; ALTER TYPE bark DROP ATTRIBUTE four; ALTER TYPE bark DROP ATTRIBUTE five; ALTER TYPE bark ADD ATTRIBUTE one text; ALTER TYPE bark ADD ATTRIBUTE three text; ALTER TYPE bark ADD ATTRIBUTE forty uuid; ALTER TYPE bark ADD ATTRIBUTE five text; ALTER TYPE bark ADD ATTRIBUTE six uuid; With these changes we'd now get: ALTER TYPE bark DROP ATTRIBUTE two; ALTER TYPE bark RENAME ATTRIBUTE four TO forty; ALTER TYPE bark ADD ATTRIBUTE six text; .. except now those are also nicely indented to be more readable for types with long schemas/type names. e.g. ALTER TYPE long_schema_name.quite_a_long_table_name ADD ATTRIBUTE "suspiciously long attribute name"? It also fixes a bug whereby if you have a precision specified, the word COLLATE mysteriously appears after the type whether or not you have a collation assigned because the collation condition was based on the precision being present for some reason. And if you actually assigned a collation for a valid data type, it wouldn't appear at all, so that's fixed too. -- Thom Brown Twitter: @darkixion IRC (freenode): dark_ixion Registered Linux user: #516935 EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company
diff --git a/pgadmin/dlg/dlgType.cpp b/pgadmin/dlg/dlgType.cpp index 5f3a36c..b951d7b 100644 --- a/pgadmin/dlg/dlgType.cpp +++ b/pgadmin/dlg/dlgType.cpp @@ -285,6 +285,7 @@ int dlgType::Go(bool modal) memberLengths.Add(typeLength); memberPrecisions.Add(typePrecision); memberCollations.Add(elements.Item(i + 2)); + memberOriginalNames.Add(elements.Item(i)); } cbDatatype->Enable(changeok); @@ -533,6 +534,7 @@ void dlgType::OnMemberAdd(wxCommandEvent &ev) memberLengths.Add(length); memberPrecisions.Add(precision); memberCollations.Add(collation); + memberOriginalNames.Add(wxEmptyString); } CheckChange(); @@ -574,10 +576,12 @@ void dlgType::OnMemberChange(wxCommandEvent &ev) memberLengths.Insert(length, pos); memberPrecisions.Insert(precision, pos); memberCollations.Insert(collation, pos); +// memberOriginalNames.Insert(name, pos); memberTypes.RemoveAt(pos + 1); memberLengths.RemoveAt(pos + 1); memberPrecisions.RemoveAt(pos + 1); memberCollations.RemoveAt(pos + 1); +// memberOriginalNames.RemoveAt(pos + 1); } } @@ -596,6 +600,7 @@ void dlgType::OnMemberRemove(wxCommandEvent &ev) memberLengths.RemoveAt(pos); memberPrecisions.RemoveAt(pos); memberCollations.RemoveAt(pos); + memberOriginalNames.RemoveAt(pos); } CheckChange(); } @@ -833,7 +838,7 @@ wxString dlgType::GetFullTypeName(int type) typname += wxT(",") + memberPrecisions.Item(type); typname += wxT(")"); } - if (!memberPrecisions.Item(type).IsEmpty() && memberPrecisions.Item(type) != wxT("pg_catalog.\"default\"")) + if (!memberCollations.Item(type).IsEmpty() && memberCollations.Item(type) != wxT("pg_catalog.\"default\"")) typname += wxT(" COLLATE ") + memberCollations.Item(type); return typname; @@ -842,46 +847,78 @@ wxString dlgType::GetFullTypeName(int type) wxString dlgType::GetSqlForTypes() { wxString sql = wxEmptyString; - wxString old_name, old_type, old_collation, new_name, new_type, new_collation; + wxString objname, old_name, old_type, old_collation, new_name, new_type, new_collation, original_name; wxArrayString elements = type->GetTypesArray(); - bool modified = lstMembers->GetItemCount() * 3 != (int)elements.GetCount(); - size_t i; + size_t newindex; + size_t oldindex = 0; + int hold = 0; + objname = schema->GetQuotedPrefix() + qtIdent(GetName()); - // Check if there is a change - for (int i = 0 ; i < lstMembers->GetItemCount() && !modified; i++) + for (newindex = 0 ; newindex < lstMembers->GetItemCount() ; newindex = newindex + 1 - hold) { - old_name = elements.Item(i * 3); - old_type = elements.Item(i * 3 + 1); - old_collation = elements.Item(i * 3 + 2); - new_name = lstMembers->GetItemText(i); - new_type = GetFullTypeName(i); - new_collation = memberCollations.Item(i); - modified = modified || old_name != new_name - || old_type != new_type - || old_collation != new_collation; - } + // this will decide whether we progress to the next new item, + // or whether we need to continue checking the old list first + hold = 0; - if (modified) - { - // Drop all old attributes - for (i = 0 ; i < elements.GetCount() ; i += 3) + // these are a copy of the list before any changes + if (elements.GetCount() >= (oldindex * 3) + 3) { - old_name = elements.Item(i); - sql += wxT("ALTER TYPE ") + type->GetName() + wxT("\n DROP ATTRIBUTE ") + old_name + wxT(";\n"); + old_name = elements.Item(oldindex * 3); + old_type = elements.Item(oldindex * 3 + 1); + old_collation = elements.Item(oldindex * 3 + 2); } + // this is the original name of the type before editing + original_name = memberOriginalNames.Item(newindex); - // Add all new attributes - for (int i = 0 ; i < lstMembers->GetItemCount() ; i++) + new_name = lstMembers->GetItemText(newindex); + new_type = GetFullTypeName(newindex); + new_collation = memberCollations.Item(newindex); + + if (connection->BackendMinimumVersion(9, 1) && !original_name.IsEmpty() + && original_name != new_name && original_name == old_name + && old_type == new_type && old_collation == new_collation) { - new_name = lstMembers->GetItemText(i); - new_type = GetFullTypeName(i); - new_collation = memberCollations.Item(i); - sql += wxT("ALTER TYPE ") + type->GetName() + wxT("\n ADD ATTRIBUTE ") - + new_name + wxT(" ") + new_type; - if (!new_collation.IsEmpty() && new_collation != wxT("pg_catalog.\"default\"")) - sql += wxT(" COLLATE ") + new_collation; - sql += wxT(";\n"); + // if this was originally in the list and the name has changed then rename it + + sql += wxT("ALTER TYPE ") + objname + wxT("\n RENAME ATTRIBUTE ") + + qtIdent(original_name) + wxT(" TO ") + qtIdent(new_name) + wxT(";\n"); } + else if (!original_name.IsEmpty() && original_name != old_name) + { + // the old attribute isn't in the new list so drop it + + // don't move through new list yet + hold = 1; + + sql += wxT("ALTER TYPE ") + objname + wxT("\n DROP ATTRIBUTE ") + + qtIdent(old_name) + wxT(";\n"); + } + else if (original_name == new_name) + { + // drop then add the attribute since more than the name has changed + if (new_type != old_type || new_collation != old_collation) + { + sql += wxT("ALTER TYPE ") + objname + wxT("\n DROP ATTRIBUTE ") + + qtIdent(old_name) + wxT(";\n"); + + sql += wxT("ALTER TYPE ") + objname + wxT("\n ADD ATTRIBUTE ") + + qtIdent(new_name) + wxT(" ") + new_type + wxT(";\n"); + } + + // but do nothing if nothing has changed + } + else + { + // add new attribute as it doesn't have an original name and isn't in the old list + + sql += wxT("ALTER TYPE ") + objname + wxT("\n ADD ATTRIBUTE ") + + qtIdent(new_name) + wxT(" ") + new_type + wxT(";\n"); + + // we don't need to increment the old list as this is a new item + continue; + } + + oldindex++; } return sql; diff --git a/pgadmin/include/dlg/dlgType.h b/pgadmin/include/dlg/dlgType.h index d618221..8a3481b 100644 --- a/pgadmin/include/dlg/dlgType.h +++ b/pgadmin/include/dlg/dlgType.h @@ -54,7 +54,7 @@ private: void showDefinition(int panel); wxString GetFullTypeName(int type); - wxArrayString memberTypes, memberLengths, memberPrecisions, memberCollations; + wxArrayString memberTypes, memberLengths, memberPrecisions, memberCollations, memberOriginalNames; bool queriesToBeSplitted; DECLARE_EVENT_TABLE()
-- Sent via pgadmin-hackers mailing list (pgadmin-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers