## Code Analysis ### BY DEFAULT identity conversion does not build a generated expression `server/ast/column_table_def.go:91-111` ```go var generated vitess.Expr hasGeneratedExpr := node.IsComputed() && node.Computed.Expr != nil computedByDefaultAsIdentity := node.IsComputed() && !hasGeneratedExpr && node.Computed.ByDefault computedAsIdentity := node.IsComputed() && !hasGeneratedExpr && !node.Computed.ByDefault if hasGeneratedExpr { generated, err = nodeExpr(ctx, node.Computed.Expr) if err != nil { return nil, err } } else if computedAsIdentity { generated, err = nodeExpr(ctx, &tree.FuncExpr{ Func: tree.WrapFunction("nextval"), Exprs: tree.Exprs{ tree.NewStrVal(DoltCreateTablePlaceholderSequenceName), }, }) if err != nil { return nil, err } } ``` `computedByDefaultAsIdentity` is true for `GENERATED BY DEFAULT AS IDENTITY`, but that branch is not included in the `generated` assignment. The `nextval` placeholder is constructed only for `computedAsIdentity` (the non-BY-DEFAULT identity form). ### Column metadata is derived from the missing expression `server/ast/column_table_def.go:118-150` ```go if node.IsSerial || computedByDefaultAsIdentity || computedAsIdentity { if resolvedType.IsEmptyType() { return nil, errors.Errorf("serial type was not resolvable") } switch resolvedType.ID { case pgtypes.Int16.ID: resolvedType = pgtypes.Int16Serial case pgtypes.Int32.ID: resolvedType = pgtypes.Int32Serial case pgtypes.Int64.ID: resolvedType = pgtypes.Int64Serial default: return nil, errors.Errorf(`type "%s" cannot be serial`, resolvedType.String()) } if defaultExpr != nil { return nil, errors.Errorf(`multiple default values specified for column "%s"`, node.Name) } colDef := &vitess.ColumnDefinition{ Name: vitess.NewColIdent(string(node.Name)), Type: vitess.ColumnType{ Type: convertType.Type, ResolvedType: resolvedType, Null: isNull, NotNull: isNotNull, Autoincrement: false, Default: defaultExpr, Length: convertType.Length, Scale: convertType.Scale, KeyOpt: keyOpt, GeneratedExpr: generated, Stored: generated != nil, }, } ``` The identity flags cause the resolved integer type to become a serial type, but the BY DEFAULT path leaves `generated` nil. Consequently this converter emits no generated expression and `Stored` is false, matching the observed ordinary-column metadata and blank inserted values. ### ALTER TABLE uses the same converter `server/ast/alter_table.go:258-266` ```go func nodeAlterTableAddColumn(ctx *Context, node *tree.AlterTableAddColumn, tableName vitess.TableName, ifExists bool) (*vitess.DDL, error) { vitessColumnDef, err := nodeColumnTableDef(ctx, node.ColumnDef) if err != nil { return nil, err } tableSpec := &vitess.TableSpec{} tableSpec.AddColumn(vitessColumnDef) ``` The tested `ALTER TABLE ... ADD COLUMN` path delegates directly to `nodeColumnTableDef`, so the missing BY DEFAULT expression applies to this schema change. ## Observed Execution ### DDL and readback The local PostgreSQL wire-protocol probe ran the following test SQL. Connection credentials are omitted. ```sql DROP TABLE IF EXISTS bf_bound_1; CREATE TABLE bf_bound_1 (id INT PRIMARY KEY, source TEXT, ordinary TEXT); INSERT INTO bf_bound_1 (id,source,ordinary) VALUES (1,'alpha','plain'); ALTER TABLE bf_bound_1 ADD COLUMN arithmetic INT GENERATED ALWAYS AS (id + 10) STORED; ALTER TABLE bf_bound_1 ADD COLUMN function_form TEXT GENERATED ALWAYS AS (upper(source)) STORED; ALTER TABLE bf_bound_1 ADD COLUMN identity_form INT GENERATED BY DEFAULT AS IDENTITY; SELECT ordinal_position, column_name, column_default, is_generated, generation_expression FROM information_schema.columns WHERE table_name='bf_bound_1' ORDER BY ordinal_position; INSERT INTO bf_bound_1 (id,source,ordinary) VALUES (2,'beta','plain2'); SELECT id,source,ordinary,arithmetic,function_form,identity_form FROM bf_bound_1 ORDER BY id; SELECT column_name, is_identity, identity_generation, identity_start, identity_increment FROM information_schema.columns WHERE table_name='bf_bound_1' ORDER BY ordinal_position; SELECT attname, attgenerated, attidentity FROM pg_attribute WHERE attrelid='bf_bound_1'::regclass AND attnum > 0 ORDER BY attnum; ``` ### catalog and row output ```text ordinal_position | column_name | column_default | is_generated | generation_expression ------------------+---------------+----------------+--------------+----------------------- 4 | arithmetic | | ALWAYS | 5 | function_form | | ALWAYS | 6 | identity_form | | NEVER | id | source | ordinary | arithmetic | function_form | identity_form ----+--------+----------+------------+---------------+--------------- 1 | alpha | plain | 11 | ALPHA | 2 | beta | plain2 | 12 | BETA | column_name | is_identity | identity_generation ---------------+-------------+--------------------- identity_form | NO | attname | attgenerated | attidentity ---------------+--------------+------------- identity_form | | ``` The arithmetic and function-generated columns computed values for both rows. The identity declaration was accepted, but its catalog row reported `is_generated = NEVER` and `is_identity = NO`; the inserted `identity_form` values were blank. ### Result The captured DDL and catalog/readback output demonstrate that `GENERATED BY DEFAULT AS IDENTITY` is accepted without identity metadata or automatic values. The source path explains the failure: the BY DEFAULT branch converts the type but never supplies the generated sequence expression. ### Test context The report records no mocks, stubs, or bypasses. The probe used a local PostgreSQL wire-protocol connection and unique local test data; the observed result is from the server DDL/DML path.