[MDEV-21593] from_unixtime can not be longer used in Virtual Column Created: 2020-01-29  Updated: 2023-04-27

Status: Stalled
Project: MariaDB Server
Component/s: Data Definition - Create Table
Affects Version/s: 10.4.12
Fix Version/s: 10.4, 10.5

Type: Bug Priority: Major
Reporter: Roy Bellingan Assignee: Oleksandr Byelkin
Resolution: Unresolved Votes: 3
Labels: None
Environment:

OpenSuse 15.1


Issue Links:
Problem/Incident
is caused by MDEV-21249 MariaDB 10.3.10 When referring to bi... Closed

 Description   

This is no longer accept since the 10.4.12

CREATE TABLE `expenditure2` (
  `ts` int(10) unsigned NOT NULL COMMENT 'midnight',
  `dateUTC` date AS (cast(from_unixtime(`ts`) as date)) PERSISTENT
) ENGINE=InnoDB;

But if you already have a table with similar schema, is still working.

I check in the doc / release note and the only possibly related entry I was able to find are:
https://mariadb.com/kb/en/mariadb-10231-changelog/
https://github.com/MariaDB/server/commit/8eec2d61fc

MDEV-21249 MariaDB 10.3.10 When referring to bigint to generate timestamp data in the virtual generated column, the value of the generated column does not change when the time zone changes

As a side note also the `

create table like xxx

` no longer work so

create table newTable like tableWithVirtColum;

Gives
Error in query (1901): Function or expression 'from_unixtime()' cannot be used in the GENERATED ALWAYS AS clause of `dateCET`



 Comments   
Comment by Sergei Golubchik [ 2020-01-29 ]

This is, unfortunately, intentional.

The behavior was changed as a fix for a bug MDEV-21249. The logic is that if the function's return value depends on the session variables, it cannot be used in a persistent generated column or in an indexed virtual column. When we did it, we missed the fact that FROM_UNIXTIME depends on the current session @@time_zone value.

Thus, if you change @@time_zone and select from your existing table, you will see that column's value won't match the result of cast(from_unixtime(`ts`) as date)

Comment by Roy Bellingan [ 2020-02-04 ]

Thank you Sergei.

Do you know of any work around ? Basically we use this virtual column to convert from unix_timestamp to a datetime for easier user interaction...

Due to Virtual column not supporting Stored Procedure / Stored Functions the real solution should be able to have a function FROM_UNIXTIME(ts, timezone), if you can send me some link on how to create such a function I will try to provide a pull request. (it should be a matter of read a value passed to the function instead of the global one right ?)

As a side note documentation need to be updated in https://mariadb.com/kb/en/generated-columns/ you can read
In MariaDB 10.2.1 and later, the following statements apply to expressions for generated columns:
Non-deterministic built-in functions are supported in expressions for PERSISTENT generated columns.

Comment by Sergei Golubchik [ 2020-02-04 ]

An easy workaround would be to make the column VIRTUAL and not PERSISTENT. You'll save some disk space too.

Correct, FROM_UNIXTIME(ts, timezone) this is how we typically solve this. E.g. MDEV-11553 introduced a 3-argument version of DATE_FORMAT exactly for this reason. If you're still interested in doing a pull request after the workaround above, just say so and I'd be happy to provide some pointers.

Thanks! The documentation got it wrong for some reason. I've corrected it now.

By the way, Jira is sending you email notifications for new comments and status changes, and they all bounce back. Is this your email address still valid?

Comment by Roy Bellingan [ 2020-02-04 ]

Hi Sergei, you are right, mail was of a previous company...

This is a nice suggestion about the VIRTUAL, it will not be index-able, but yes is a nice idea...

About the MDEV-11553, Yes is fine for me to try out to add FROM_UNIXTIME(ts, timezone)

I will start from https://github.com/MariaDB/server/commit/80b9ce359312c1520623531bf173ee048317fee3

Thank you

Comment by Roy Bellingan [ 2020-04-12 ]

Hi @Sergei Golubchik, I sadly had the time to prepare the patch
I hope formatting and all is correct, there is a decent amount of comment in the code too..
If you think is ok I will do a merge request

https://gist.github.com/RoyBellingan/3c9d95c3fbdbeb61aaeb9e69d84f963a

Comment by Patrick Winter [ 2020-04-18 ]

Hello, I have the same problem and I think it should not be marked as closed yet, until Roy's patch (thank you!) is integrated. I hope it will already be merged into 10.4.13.

Comment by Daniel Black [ 2020-05-16 ]

RoyBellingan, how's your patch going?

Comment by Sergei Golubchik [ 2020-05-18 ]

danblack, there's that problem that 2-argument version of FROM_UNIXTIME already exists. Like (from the manual)

SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(), '%Y %D %M %h:%i:%s %x');

I don't know who thought it'd be a great idea to embed DATE_FORMAT into FROM_UNIXTIME to save few keystrokes, but here we are. We can, of course, say that when the format is NULL it means the default format of '%Y-%m-%d %H:%i:%S.%f' and indeed, that's what RoyBellingan did in his patch. But it looks like a hack (which is it).

It's a bit simpler for UNIX_TIMESTAMP that only has a 1-argument form, so 2-argument.

One option could be something like FROM_UNIXTIME(expr1 [, expr2] [USING time_zone ]) and the same for UNIX_TIMESTAMP(). But special keyword syntax is kind of evil too

Comment by Roy Bellingan [ 2020-06-08 ]

Thank you for the feedback.
Daniel Black suggested me to "don't go overboard in accepting multiple versions of empty format strings, NULL is probably sufficient, 0 looks odd, and "" is a bit inconsistent with the two args form (will generate a different result, if you happen to specify a timezone), so keep it simple"

I have now to understand how to write and run the test.

Comment by Patrick Winter [ 2020-06-24 ]

Please, can someone change the status of this issue to Open?

I still have this problem, and the workaround with PERSISTENT does not work for me because my database is large, there is JSON involved and the select times would increase dramatically.

I really would need that patch Roy Bellingan, if it is finished yet, and I hope it is included in the next version of MariaDB.

Comment by Roy Bellingan [ 2020-06-29 ]

Hi Daniel, I did a few test case https://gist.github.com/RoyBellingan/3c9d95c3fbdbeb61aaeb9e69d84f963a

3 new files, in the main section, called timezone5, I used timezone4 as a template
I also had to change the main/parser.test and remove the check in using a 3 value format.

But IS NOT WORKING when used under a view, because in the FRM file is not saved the 3 arg but only the first.... still investiganting why.

Comment by Daniel Black [ 2020-07-23 ]

RoyBellingan sorry for getting distracted on this. I'm around so start up a zulip topic, ping me and show a ref to your current code and I'll give it a closer look.

Comment by Patrick Winter [ 2020-08-05 ]

Good to hear this is still worked on. Any progress? Actually, to me it looks more like a mere syntax problem.

Comment by Roy Bellingan [ 2020-08-05 ]

@patrick it became much a bit more difficult than expect...
Ongoing developement is here https://github.com/RoyBellingan/server/pull/1 but at the moment Is stalled due to me beeing a bit busy.

What needs to be done now is a good numer of test cases, covering many area...

Comment by Chris Wilson [ 2020-12-03 ]

I think this is workaround-able. We can simply avoid using from_unixtime() and instead rely upon the fact that date_add ignores timezones (this is a feature, not a bug, right?); so this is an equivalent to from_unixtime always in UTC:-

drop temporary table if exists test1;
create temporary table test1 (
ts bigint not null,
asdate datetime as (date_add("1970-1-1 00:00:00", interval ts second)) persistent
) engine=innodb;

Or if you want a different timezone then just convert explicitly:-

drop temporary table if exists test1;
create temporary table test1 (
ts bigint not null,
asdate datetime as (convert_tz(date_add("1970-1-1 00:00:00", interval ts second), "UTC", "Europe/London")) persistent
) engine=innodb;
 
insert into test1 (ts) values (1), (1606993464), (1603587540), (1603587600);
select * from test1;

Comment by Roy Bellingan [ 2020-12-03 ]

This is a very cool idea!
Amazing

Generated at Thu Feb 08 09:08:19 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.