Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,20 @@ def get_oftype(self, gid, sid, did, scid, tid=None):
if not status:
return internal_server_error(errormsg=type_cols)

# Mark columns as inherited from type (not table)
# so the UI allows editing defaults/constraints
# Also store original values for comparison later
for col in type_cols['rows']:
if 'inheritedfrom' in col:
col['inheritedfromtype'] = col['inheritedfrom']
# Keep inheritedfrom for backward compatibility
# but UI will check inheritedfromtype first

# Store original values from the composite type
# This allows backend to detect actual modifications
col['original_defval'] = col.get('defval')
col['original_attnotnull'] = col.get('attnotnull', False)

res.append({
'label': row['typname'],
'value': row['typname'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ export default class ColumnSchema extends BaseUISchema {
return { cell: this.attlenRange(state) ? 'int' : '' };
}

isInheritedFromType(state) {
return !isEmptyString(state.inheritedfromtype);
}

get baseFields() {
let obj = this;

Expand Down Expand Up @@ -284,6 +288,30 @@ export default class ColumnSchema extends BaseUISchema {
}
return false;
},
},{
/* This field is used to track inheritance from composite types */
id: 'inheritedfromtype',
label: gettext('Inherited from type'),
type: 'text',
visible: false,
},{
/* This field is used to track inheritance from parent tables */
id: 'inheritedfromtable',
label: gettext('Inherited from table'),
type: 'text',
visible: false,
},{
/* Store original DEFAULT from composite type to detect modifications */
id: 'original_defval',
label: gettext('Original Default'),
type: 'text',
visible: false,
},{
/* Store original NOT NULL from composite type to detect modifications */
id: 'original_attnotnull',
label: gettext('Original NOT NULL'),
type: 'boolean',
visible: false,
},{
id:'geometry', label: gettext('Geometry Type'), deps: ['cltype'],
group: gettext('Definition'), type: 'select', options: this.geometryTypes,
Expand Down Expand Up @@ -465,19 +493,28 @@ export default class ColumnSchema extends BaseUISchema {
disabled: function(state) {
let isDisabled = ['serial', 'bigserial', 'smallserial'].indexOf(state.cltype) > -1;
isDisabled = isDisabled || state.colconstype != 'n';
if(!isDisabled && this.isInheritedFromType(state)) {
return isDisabled = false;
}
return isDisabled;
}, depChange: (state)=>{
let isDisabled = false;
if(!obj.inSchemaWithModelCheck(state)) {
isDisabled = ['serial', 'bigserial', 'smallserial'].indexOf(state.cltype) > -1;
}
isDisabled = isDisabled || state.colconstype != 'n';
if (isDisabled && obj.isNew(state)) {
// Allow editing for OF TYPE columns, but block for table inheritance
if (isDisabled && obj.isNew(state) && !this.isInheritedFromType(state)) {
return {defval: undefined};
}
}, editable: function(state) {
// Allow editing for OF TYPE columns (inheritedfromtype)
// But block editing for parent table inheritance (inheritedfromtable or inheritedfrom without inheritedfromtype)
if (this.isInheritedFromType(state)) {
return true;
}
// inheritedfrom has value then we should disable it
return !(!isEmptyString(state.inheritedfrom) || !this.editableCheckForTable(state));
return this.editableCheckForTable(state);
},
},{
id: 'attnotnull', label: gettext('Not NULL?'), cell: 'switch',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,59 @@ 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 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)

# Now we have all lis of columns which we need
# to include in our create definition, Let's format them
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ export class LikeSchema extends BaseUISchema {
}

resetVals(state) {
if(this.isRelationDisable(state) && this.top.isNew()) {
if(this.isRelationDisable(state) && this.top && this.top.isNew()) {
return {
like_default_value: false,
like_constraints: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)}} {% 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 %}
{% 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 %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,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 != '' and c.colconstype != 'g' %} 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 != '' and c.colconstype != 'g' %} 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 != '' and c.colconstype != 'g' %} DEFAULT {{c.defval}}{% endif %}{% endif %}
{% 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 %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,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.attcompression is defined and c.attcompression is not none and c.attcompression != '' %} COMPRESSION {{c.attcompression}}{% 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 != '' and c.colconstype != 'g' %} 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.attcompression is defined and c.attcompression is not none and c.attcompression != '' %} COMPRESSION {{c.attcompression}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' and c.colconstype != 'g' %} 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.attcompression is defined and c.attcompression is not none and c.attcompression != '' %} COMPRESSION {{c.attcompression}}{% 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 != '' and c.colconstype != 'g' %} DEFAULT {{c.defval}}{% endif %}{% endif %}
{% 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 %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,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.attstorage is defined and c.attstorage != c.defaultstorage%} STORAGE {%if c.attstorage == 'p' %}PLAIN{% elif c.attstorage == 'm'%}MAIN{% elif c.attstorage == 'e'%}EXTERNAL{% elif c.attstorage == 'x'%}EXTENDED{% elif c.attstorage == 'd'%}DEFAULT{% endif %}{% endif %}{% if c.attcompression is defined and c.attcompression is not none and c.attcompression != '' %} COMPRESSION {{c.attcompression}}{% 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 != '' and c.colconstype != 'g' %} 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.attstorage is defined and c.attstorage != c.defaultstorage%} STORAGE {%if c.attstorage == 'p' %}PLAIN{% elif c.attstorage == 'm'%}MAIN{% elif c.attstorage == 'e'%}EXTERNAL{% elif c.attstorage == 'x'%}EXTENDED{% elif c.attstorage == 'd'%}DEFAULT{% endif %}{% endif %}{% if c.attcompression is defined and c.attcompression is not none and c.attcompression != '' %} COMPRESSION {{c.attcompression}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' and c.colconstype != 'g' %} 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.attstorage is defined and c.attstorage != c.defaultstorage%} STORAGE {%if c.attstorage == 'p' %}PLAIN{% elif c.attstorage == 'm'%}MAIN{% elif c.attstorage == 'e'%}EXTERNAL{% elif c.attstorage == 'x'%}EXTENDED{% elif c.attstorage == 'd'%}DEFAULT{% endif %}{% endif %}{% if c.attcompression is defined and c.attcompression is not none and c.attcompression != '' %} COMPRESSION {{c.attcompression}}{% 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 != '' and c.colconstype != 'g' %} DEFAULT {{c.defval}}{% endif %}{% endif %}
{% 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 %}
Expand Down
Loading
Loading