Skip to content
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

Default expression is not loaded into ColumnSchema #19747

Open
SOHELAHMED7 opened this issue Jan 23, 2023 · 8 comments
Open

Default expression is not loaded into ColumnSchema #19747

SOHELAHMED7 opened this issue Jan 23, 2023 · 8 comments
Assignees

Comments

@SOHELAHMED7
Copy link
Contributor

SOHELAHMED7 commented Jan 23, 2023

When column schema is loaded from DB, for columns having default value as expression but not constant, I get expression as string as default value instead of object of \yii\db\Expression.

Example:

What steps will reproduce the problem?

  • create a new table with at least one column that have default expression. Example:
$mysqlColumns = [
            'ts' => 'datetime DEFAULT \'2011-11-11 00:00:00\'',
            'ts2' => 'datetime DEFAULT CURRENT_TIMESTAMP',
            'ts3' => 'datetime DEFAULT CURRENT_TIMESTAMP',
            'ts4' => 'timestamp DEFAULT CURRENT_TIMESTAMP',
            'ts5' => 'timestamp DEFAULT \'2011-11-11 00:00:00\'',
            'ts6' => 'timestamp DEFAULT CURRENT_TIMESTAMP',
            'd' => 'date DEFAULT \'2011-11-11\'',
            'd2' => 'text', // DEFAULT "2011-11-11"
            'd3' => 'text', // DEFAULT CURRENT_DATE + INTERVAL 1 YEAR
            'ts7' => 'date DEFAULT (CURRENT_DATE + INTERVAL 2 YEAR)',
        ];
        if (DB::isPostgres()) {
            $pgsqlColumns = $mysqlColumns;
            $pgsqlColumns['ts7'] = 'date DEFAULT (CURRENT_DATE + INTERVAL \'2 YEAR\')';
            Yii::$app->db->createCommand()->createTable('{{%fruits}}', $pgsqlColumns)->execute();
            return;
        }

        Yii::$app->db->createCommand()->createTable('{{%fruits}}', $mysqlColumns)->execute();
  • now get columns schema from yii\db\TableSchema::$columns
  • say for e.g. lets take ts7 column from example $ts7ColumnSchema = (object of yii\db\TableSchema)::$columns['ts7']

What is the expected result?

Now I expect $ts7ColumnSchema->defaultValue should be equal to object of \yii\db\Expression('(CURRENT_DATE + INTERVAL 2 YEAR)'') for Mysql

What do you get instead?

I get $ts7ColumnSchema->defaultValue as '(CURRENT_DATE + INTERVAL 2 YEAR)' as string

Hint for solution

For MySQL we get DEFAULT_GENERATED in Extra column, we can use that when we loadColumnSchema()

mysql-def-expr

For PgSQL for default constant, its value is suffixed by ::data_type e.g. ::text

pgsql-def-exp

Additional info

Q A
Yii version 2.0.*
PHP version
Operating system
@samdark
Copy link
Member

samdark commented Jan 23, 2023

Doesn't look good. Do you have a time for a fix?

@SOHELAHMED7
Copy link
Contributor Author

What doesn't look good?

Do you have a time for a fix?

cannot say concretely. But I will try. If I take this issue in hand, can I introduce breaking change if it is needed? At this moment I cannot say that my PR will have breaking change (also I will try to avoid as much as possible) but if I need to choose a path for solution that might break something (e.g. method signature of public method), can I proceed on that path?

@samdark
Copy link
Member

samdark commented Jan 24, 2023

@SOHELAHMED7 if breaking change is unavoidable, feel free to do it. But it's better to avoid it.

@SOHELAHMED7
Copy link
Contributor Author

I came to know that for MariaDB I don't get DEFAULT_GENERATED in Extra column (see this image for MySQL for corresponding data)

I just get empty data in Extra

So for Mariadb it is very hard to detect that default value is constant or expression:

mariadb-default-values

At this moment I am skipping implementation for this issue for Mariadb

Any hint to fix this issue for Mariadb is more than welcome

@SOHELAHMED7
Copy link
Contributor Author

For Mariadb

While getting info from INFORMATION_SCHEMA

info-schema-column

I get default value

  • number without quotes
  • string with quotes
  • expression as string without quotes

It will allow me to check if it is non-empty string without quotes it is expression.

Though I don't think it is 💯 perfect solution, but I will proceed with this in case of Mariadb

@SOHELAHMED7
Copy link
Contributor Author

Note:

For table

CREATE TABLE  IF NOT EXISTS `datetime_test`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

for column 'ts', in Extra column

for MySQL we get 'DEFAULT_GENERATED on update CURRENT_TIMESTAMP'

for Maria we get 'on update current_timestamp()'

@SOHELAHMED7
Copy link
Contributor Author

Tests for Mariadb

I am facing difficulties mocking methods/properties (below) that make db = mariadb in tests

public function isMysql()
    {
        return ($this->db->schema instanceof static && !$this->isMariaDb());
    }
    
    public function isMariaDb()
    {
        return strpos($this->db->schema->getServerVersion(), 'MariaDB') !== false;
    }

Also if I use real MariaDB server, I have to setup Mariadb in Github action.

So I have decided to proceed with tests for Mariadb in below way:

I will write tests for Mariadb that will connect with my real local Mariadb server. I will add condition, if db !== mariadb; skip this tests. So theses tests will always be skipped in Github actions but will run if connected to local Mariadb server.

@SOHELAHMED7
Copy link
Contributor Author

After several attempts and a question at Stack Overflow, detecting default value is constant or expression in PgSQL is complex/not possible/requires lots of unreliable if condition. So I will skip implementation of this issue for PgSQL.

@samdark samdark added this to the 2.0.49 milestone May 21, 2023
@bizley bizley modified the milestones: 2.0.49, 2.0.50 Aug 29, 2023
@bizley bizley modified the milestones: 2.0.49.1, 2.0.50 Oct 5, 2023
@samdark samdark removed this from the 2.0.50 milestone May 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants