-
Notifications
You must be signed in to change notification settings - Fork 818
Allow users to customize ofType columns during table creation #223 #9580
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -364,9 +364,63 @@ def parse_format_columns(data, mode=None): | |
| # tables 'CREATE' mode | ||
| final_columns = [] | ||
|
|
||
| # Get list of columns in primary key constraint | ||
| pk_columns = set() | ||
| if 'primary_key' in data and len(data['primary_key']) > 0: | ||
| for pk in data['primary_key']: | ||
| if 'columns' in pk: | ||
| for col in pk['columns']: | ||
| if 'column' in col: | ||
| pk_columns.add(col['column']) | ||
|
|
||
| for c in columns: | ||
| # Include non-inherited columns | ||
| if c.get('inheritedfrom', None) is None: | ||
| final_columns.append(c) | ||
| # Also include columns inherited from composite types (OF TYPE) | ||
| # that have modifications (WITH OPTIONS clause) | ||
| elif c.get('inheritedfromtype', None) is not None: | ||
| # Check if column has been modified or is in a constraint | ||
| has_modifications = False | ||
|
|
||
| # Check if column is in PRIMARY KEY constraint | ||
| # Note: We don't include the column for PRIMARY KEY because | ||
| # it's added as a separate table-level constraint | ||
| # Uncomment this if you want column-level PRIMARY KEY: | ||
| # if c.get('name') in pk_columns: | ||
| # has_modifications = True | ||
|
|
||
| # Check for PRIMARY KEY (marked via is_primary_key checkbox) | ||
| if c.get('is_primary_key'): | ||
| has_modifications = True | ||
|
|
||
| # Check if DEFAULT value was actually modified | ||
| # (different from type) | ||
| original_defval = c.get('original_defval') | ||
| current_defval = c.get('defval') | ||
| # Compare as strings, treating None and empty string | ||
| # as equivalent | ||
| orig_val = str(original_defval) \ | ||
| if original_defval is not None else '' | ||
| curr_val = str(current_defval) \ | ||
| if current_defval is not None else '' | ||
| if orig_val != curr_val: | ||
| has_modifications = True | ||
|
|
||
| # Check if NOT NULL was actually modified | ||
| # (different from type) | ||
| original_attnotnull = c.get('original_attnotnull', False) | ||
| current_attnotnull = c.get('attnotnull', False) | ||
| if original_attnotnull != current_attnotnull: | ||
| has_modifications = True | ||
|
|
||
| if has_modifications: | ||
| # Mark this column to use WITH OPTIONS syntax in template | ||
| # Skip identity columns as WITH OPTIONS | ||
| # cannot be combined with GENERATED ALWAYS AS IDENTITY | ||
| if c.get('colconstype') != 'i': | ||
| c['has_with_options'] = True | ||
| final_columns.append(c) | ||
|
Comment on lines
+386
to
+423
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's understand the file structure and locate the template that uses has_with_options
find web -name "*.sql" -o -name "*.j2" -o -name "*.jinja*" | head -20Repository: pgadmin-org/pgadmin4 Length of output: 2188 🏁 Script executed: # Search for has_with_options usage in the codebase
rg "has_with_options" --type py --type sql -B 2 -A 2Repository: pgadmin-org/pgadmin4 Length of output: 11388 🏁 Script executed: # Get more context around the code in question - show the full function
cd web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns && \
wc -l utils.py && \
head -n 430 utils.py | tail -n 100Repository: pgadmin-org/pgadmin4 Length of output: 4144 🌐 Web query:
💡 Result: Yes. In PostgreSQL the
So Citations:
Remove the The code marks columns for Suggested change- # Check for PRIMARY KEY (marked via is_primary_key checkbox)
- if c.get('is_primary_key'):
- has_modifications = True🤖 Prompt for AI Agents
Comment on lines
+367
to
+423
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's read the complete function to understand the full context
wc -l web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.pyRepository: pgadmin-org/pgadmin4 Length of output: 151 🏁 Script executed: # Read the function around lines 367-423 with more context
sed -n '340,450p' web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.pyRepository: pgadmin-org/pgadmin4 Length of output: 4313 🏁 Script executed: # Search for how has_with_options is used in the codebase
rg 'has_with_options' --type py -B 2 -A 2Repository: pgadmin-org/pgadmin4 Length of output: 708 🏁 Script executed: # Search for WITH OPTIONS in template files to understand SQL generation
rg 'WITH OPTIONS' --type-listRepository: pgadmin-org/pgadmin4 Length of output: 453 🏁 Script executed: # Also search for any SQL templates that use this flag
find . -name '*.sql' -o -name '*.jinja2' | head -20Repository: pgadmin-org/pgadmin4 Length of output: 2228 🏁 Script executed: # Search for table creation templates in the tables directory
find web/pgadmin/browser/server_groups/servers/databases/schemas/tables -name '*.sql' -o -name '*.jinja2' | head -30Repository: pgadmin-org/pgadmin4 Length of output: 3907 🏁 Script executed: # Search for how has_with_options is referenced in templates
rg 'has_with_options' --type py --type sql --type jinja2 -B 3 -A 3Repository: pgadmin-org/pgadmin4 Length of output: 94 🏁 Script executed: # Look for CREATE TABLE template files
find web/pgadmin/browser/server_groups/servers/databases/schemas/tables -type f -name '*create*' | head -20Repository: pgadmin-org/pgadmin4 Length of output: 2667 🏁 Script executed: # Find template files for tables (look for .sql files in templates directories)
find web/pgadmin/browser/server_groups/servers/databases/schemas/tables -path '*/templates/*' -type f | head -30Repository: pgadmin-org/pgadmin4 Length of output: 3542 🏁 Script executed: # Search for WITH OPTIONS in template files
rg 'WITH OPTIONS' -B 2 -A 2Repository: pgadmin-org/pgadmin4 Length of output: 12287 🏁 Script executed: # Search for the create.sql template for tables
find web/pgadmin/browser/server_groups/servers/databases/schemas/tables -name 'create.sql'Repository: pgadmin-org/pgadmin4 Length of output: 3765 🏁 Script executed: # Let me read the actual template file to see the exact syntax
cat web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/default/create.sql | grep -A 5 "has_with_options"Repository: pgadmin-org/pgadmin4 Length of output: 1592 🏁 Script executed: # Also check if there are any test cases that test WITH OPTIONS without actual options
find web/pgadmin/browser/server_groups/servers/databases/schemas/tables -path '*/tests/*' -name '*.sql' | xargs grep -l "WITH OPTIONS" 2>/dev/null | head -5Repository: pgadmin-org/pgadmin4 Length of output: 46 Remove Lines 394–423: Setting 🤖 Prompt for AI Agents |
||
|
|
||
| # Now we have all lis of columns which we need | ||
| # to include in our create definition, Let's format them | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,7 +46,7 @@ CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE{% if add_not_exists | |
| {% if data.columns and data.columns|length > 0 %} | ||
| {% for c in data.columns %} | ||
| {% if c.name and c.cltype %} | ||
| {% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.geometry and not is_sql %}({{c.geometry}}{% if c.srid %},{{c.srid}}{% endif %}){% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' %} DEFAULT {{c.defval}}{% endif %} | ||
| {% if c.inheritedfromtype and c.has_with_options %}{# Use WITH OPTIONS syntax for modified OF TYPE columns #}{{conn|qtIdent(c.name)}} WITH OPTIONS{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' %} DEFAULT {{c.defval}}{% endif %}{% elif c.inheritedfromtable %}{# Inherited from parent table - keep as comment #}-- Inherited from table {{c.inheritedfromtable}}: {{conn|qtIdent(c.name)}}{% else %}{# Regular column or inherited without modifications #}{% if c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.geometry and not is_sql %}({{c.geometry}}{% if c.srid %},{{c.srid}}{% endif %}){% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' %} DEFAULT {{c.defval}}{% endif %}{% endif %} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Template syntax error: Missing The template has a malformed conditional structure. Comparing to the other templates (11_plus, 12_plus, 14_plus), there's a missing Current (broken): {{conn|qtIdent(c.name)}}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(...) }}{% endif %}The Expected (from other templates): {{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(...) }}{% endif %}🐛 Proposed fix- {% if c.inheritedfromtype and c.has_with_options %}{# Use WITH OPTIONS syntax for modified OF TYPE columns #}{{conn|qtIdent(c.name)}} WITH OPTIONS{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' %} DEFAULT {{c.defval}}{% endif %}{% elif c.inheritedfromtable %}{# Inherited from parent table - keep as comment #}-- Inherited from table {{c.inheritedfromtable}}: {{conn|qtIdent(c.name)}}{% else %}{# Regular column or inherited without modifications #}{% if c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.geometry and not is_sql %}({{c.geometry}}{% if c.srid %},{{c.srid}}{% endif %}){% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' %} DEFAULT {{c.defval}}{% endif %}{% endif %}
+ {% if c.inheritedfromtype and c.has_with_options %}{# Use WITH OPTIONS syntax for modified OF TYPE columns #}{{conn|qtIdent(c.name)}} WITH OPTIONS{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' %} DEFAULT {{c.defval}}{% endif %}{% elif c.inheritedfromtable %}{# Inherited from parent table - keep as comment #}-- Inherited from table {{c.inheritedfromtable}}: {{conn|qtIdent(c.name)}}{% else %}{# Regular column or inherited without modifications #}{% if c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.geometry and not is_sql %}({{c.geometry}}{% if c.srid %},{{c.srid}}{% endif %}){% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' %} DEFAULT {{c.defval}}{% endif %}{% endif %}🤖 Prompt for AI Agents✅ Addressed in commit be63f61 |
||
| {% if c.colconstype == 'i' and c.attidentity and c.attidentity != '' %} | ||
| {% if c.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif c.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %} | ||
| {% if c.seqincrement or c.seqcycle or c.seqincrement or c.seqstart or c.seqmin or c.seqmax or c.seqcache %} ( {% endif %} | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wire
isInheritedFromTypeinto inherited-column edit checks.Right now the edit/readonly gates still key off
inheritedfrom, andget_oftypekeeps that field for backward compatibility. That means OF TYPE columns can remain read‑only, undermining the goal of making them editable. Please distinguish table inheritance from type inheritance in the checks (and in the directinheritedfromchecks for length/precision/default).🔧 Suggested fix
isInheritedFromType(state) { return !isEmptyString(state.inheritedfromtype); } + + isInheritedFromTable(state) { + return !isEmptyString(state.inheritedfrom) && !this.isInheritedFromType(state); + } ... - if (!isEmptyString(state.inheritedfrom)){ + if (this.isInheritedFromTable(state)){ return true; } ... - if (!isEmptyString(state.inheritedfrom)) { + if (obj.isInheritedFromTable(state)) { return false; } ... - if (!isEmptyString(state.inheritedfrom)) { + if (obj.isInheritedFromTable(state)) { return false; } ... - return !(!isEmptyString(state.inheritedfrom) || !this.editableCheckForTable(state)); + return !(obj.isInheritedFromTable(state) || !this.editableCheckForTable(state));🤖 Prompt for AI Agents