[MDEV-25015] Custom formatting of strings in MariaDB queries Created: 2021-03-01 Updated: 2023-04-07 Resolved: 2021-10-12 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Server |
| Fix Version/s: | 10.7.1 |
| Type: | Task | Priority: | Critical |
| Reporter: | Robert Bindar | Assignee: | Sergei Golubchik |
| Resolution: | Fixed | Votes: | 1 |
| Labels: | Preview_10.7, gsoc21 | ||
| Issue Links: |
|
||||||||||||||||||||||||||||||||||||||||
| Description |
|
Formatting more complex strings in a SELECT statement can get awkward when there are many concat(), format(), etc calls involved. A great example for such a function is the classic C printf function, which, in this context, would look something like:
But it doesn't necessarily need to look this way, an alternative syntax could be Python-ish, which would leverage the fact that the server already knows the datatype of each field used in the formatting scheme:
In that syntax one passes formatting options within the curly braces:
Ideally, this new function should use, behind the scenes, the existing builtin formatting functions in MariaDB (e.g. date_format(), format()) and even future formatting functions (e.g. MySQL's format_bytes(), format_pico_time()), so the syntax has to be designed in a smart way to accommodate easily future additions. |
| Comments |
| Comment by Sergei Golubchik [ 2021-03-01 ] | ||||||||||||||||||||||||||||||||
|
is there anything comparable in other DBMS-es? | ||||||||||||||||||||||||||||||||
| Comment by Sergei Golubchik [ 2021-03-27 ] | ||||||||||||||||||||||||||||||||
|
Didn't find in Oracle, DB2, or SQL Server. | ||||||||||||||||||||||||||||||||
| Comment by Sergei Golubchik [ 2021-05-12 ] | ||||||||||||||||||||||||||||||||
|
Perhaps, suggesting {%W %M %Y} wasn't such a great idea, one can always do
May be it'd be more consistent to stick to python-ish format and not allow completely different syntax inside curly braces for different types. Having PostgreSQL-like "sql literal" and "identifier" (also like %`s in my_vsnprinf()) modifiers would be quite useful, though. | ||||||||||||||||||||||||||||||||
| Comment by Sergei Golubchik [ 2021-09-05 ] | ||||||||||||||||||||||||||||||||
|
just to record the conclusion. We ended up using fmt library. Changes/limitation:
| ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-18 ] | ||||||||||||||||||||||||||||||||
|
serg Thank you for the solid MTR testcase main/func_sformat.test | ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-18 ] | ||||||||||||||||||||||||||||||||
|
serg Hi! There is a compiler error when installing libfmt-dev on Ubuntu 20.04.3 LTS and compiling:
Compiling with that package not installed or purged works fine (and SFORMAT works in that case too). | ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-18 ] | ||||||||||||||||||||||||||||||||
|
serg Looking at TODO-3121, it could be the minimum version? The standard version (from sudo apt install libfmt-dev on 20.04.3 LTS) is 6.1 (libfmt-dev_6.1.2+ds-2_amd64.deb). And, version 7 is not available by default E: Unable to locate package libfmt7-dev | ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-18 ] | ||||||||||||||||||||||||||||||||
|
Testing (without libfmt-dev installed, which works, ref question in TODO-3121) shows;
| ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-18 ] | ||||||||||||||||||||||||||||||||
|
I consider the feature OK to push. | ||||||||||||||||||||||||||||||||
| Comment by Sergei Golubchik [ 2021-09-18 ] | ||||||||||||||||||||||||||||||||
|
Roel, you should use preview-10.7- Yes, our implementation needs libfmt at least 7.0, Ubuntu's 6.1 is too old. Thanks, for pointing it out, I'll fix it. By the way, it's not my code or test cases, it's a GSoC'21 project implemented by Alan Cueva | ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-20 ] | ||||||||||||||||||||||||||||||||
|
serg Thank you. I went back to double check the logs, and that was indeed the branch I used for testing.
I see. Thank you Alan Cueva for a well done testcase. Ack on libmft. | ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-20 ] | ||||||||||||||||||||||||||||||||
|
Logged | ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-25 ] | ||||||||||||||||||||||||||||||||
|
serg Could you please add this to the testcase (subqueries were not included yet):
Thank you | ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-25 ] | ||||||||||||||||||||||||||||||||
|
Note sure if this could be considered a bug?
| ||||||||||||||||||||||||||||||||
| Comment by Sergei Golubchik [ 2021-09-25 ] | ||||||||||||||||||||||||||||||||
|
yes, let's consider it a bug. libfmt can print floats just fine, so we should pass down floats as floats without upcasting them to double. | ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-26 ] | ||||||||||||||||||||||||||||||||
|
Logged as | ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-30 ] | ||||||||||||||||||||||||||||||||
|
Though it's covered in the testcase (input (5,5,5)) should this give a warning ("extraneous inputs/parameter found") - or the existing ERROR 1582 (42000): Incorrect parameter count in the call to native function 'sformat'?
| ||||||||||||||||||||||||||||||||
| Comment by Roel Van de Paar [ 2021-09-30 ] | ||||||||||||||||||||||||||||||||
|
Further testing has not revealed any additional issues save the one above. Re-assigning back to serg for push to trunk if not done already. | ||||||||||||||||||||||||||||||||
| Comment by Federico Razzoli [ 2021-12-27 ] | ||||||||||||||||||||||||||||||||
|
Trying to use named parameters ('{name}') doesn't return a specific error, though I couldn't find a way to make it work. Please clarify how to use named parameters in the docs, or produce an error that clarifies that this is not supported. | ||||||||||||||||||||||||||||||||
| Comment by Sergei Golubchik [ 2021-12-27 ] | ||||||||||||||||||||||||||||||||
|
This is the error message that libfmt returns. And yes named parameters don't work. It'd open a very special can of worms, consider, for example,
which shoud show the value of a column which name is stored in the column col. I'm not saying it's impossible to make it work, but it'd be very complex with tons of vague corner cases. We decided not to go there for now. | ||||||||||||||||||||||||||||||||
| Comment by Federico Razzoli [ 2021-12-27 ] | ||||||||||||||||||||||||||||||||
|
I think there are ways to write obscure queries both with named and positional arguments. But it's reasonable to omit a feature from libfmt, I just think that it should be more clear. |