Skip to content

compareColumns bug: if columns depending on other columns #107

@siggi-k

Description

@siggi-k

Problem: Generated columns depending on other columns cause migration errors

Use case:
I added a column name_index which stores a tsvector generated from another column name.
This column is defined in the Lead.yaml specification (see below for context).

Lead.yaml

# Lead:
title: Lead
x-table: leads
type: object
x-indexes:
  - gin:name_index

required:
 - id
 - name
 - name_index

properties:

  id:
    type: integer
    example: 12531
    readOnly: true

  name:
    type: string
    example: 'Stefan Müller'
    maxLength: 128
    x-faker: $faker->company

  name_index:
    type: string
    x-db-type: |
      tsvector GENERATED ALWAYS AS (
          to_tsvector('simple', coalesce(name, ''))
      ) STORED
    readOnly: true
    x-faker: false

The code generator (./yii gii/api) correctly produced a migration like:

m251023_120000_change_table_leads.php

/**
 * Table for Lead
 */
class m251023_120000_change_table_leads extends \yii\db\Migration
{
    public function safeUp()
    {
        $this->db->createCommand('ALTER TABLE {{%leads}} ADD COLUMN "name_index" tsvector generated always as (
    to_tsvector(\'simple\', coalesce(name, \'\'))
) stored
 NOT NULL')->execute();
        $this->createIndex('leads_name_index_gin_index', '{{%leads}}', 'name_index', 'gin');
    }

    public function safeDown()
    {
        $this->dropIndex('leads_name_index_gin_index', '{{%leads}}');
        $this->dropColumn('{{%leads}}', 'name_index');
    }
}

This migration runs successfully in PostgreSQL (tested on version 13).
However, when I run the command again:

./yii gii/api --ignoreSpecErrors

I get the following error:

Caused by: Exception 'PDOException' with message
'SQLSTATE[42703]: Undefined column: 7 ERROR:  column "name" does not exist at character 109'

Root cause:
The problem originates in
cebe\yii2openapi\lib\migrations\BaseMigrationBuilder::tmpSaveNewCol
At line 455:
Yii::$app->db->createCommand()->createTable($tmpTableName, $column)->execute();

This code tries to create a temporary table containing the generated column name_index,
but PostgreSQL raises an error because the referenced column "name" does not exist yet in that temporary table.

Summary:
When generating migrations for generated columns (GENERATED ALWAYS AS (...) STORED) that depend on other columns, the migration builder attempts to create temporary tables without those dependencies, causing PostgreSQL to throw Undefined column errors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions