what is the meaning of select ''-'' - mysql

There is an article about SQL injection: Abusing MySQL string arithmetic for tiny SQL injections
The question is, what is the meaning of select ''-'' ? I try it with MySQL, and it returns:
mysql> select ''-'';
+-------+
| ''-'' |
+-------+
| 0 |
+-------+
1 row in set (0.00 sec)
What happend? What means that 0?
And the result of select '-':
mysql> select '-';
+---+
| - |
+---+
| - |
+---+
1 row in set (0.00 sec)
I am very confused about these result.

You are minus - from one empty string '' to other:
See following:
mysql> select '';
+--+
| |
+--+
| |
+--+
1 row in set (0.00 sec)
mysql> select '3'-'2';
+---------+
| '3'-'2' |
+---------+
| 1 |
+---------+
1 row in set (0.00 sec)
But warning if its not a number string:
mysql> select 'a'-'b';
+---------+
| 'a'-'b' |
+---------+
| 0 |
+---------+
1 row in set, 2 warnings (0.00 sec)
Two warnings:
mysql> SHOW WARNINGS LIMIT 2
-> ;
+---------+------+---------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'a' |
| Warning | 1292 | Truncated incorrect DOUBLE value: 'b' |
+---------+------+---------------------------------------+
2 rows in set (0.00 sec)
Why no warning for empty string?
Where as there is no warning for empty string because its(casted something) 0 see below:
mysql> SELECT 0 = '';
+--------+
| 0 = '' |
+--------+
| 1 |
+--------+
1 row in set (0.00 sec)
hence by doing ''-'' you are doing 0 - 0
mysql> SELECT '' - '';
+---------+
| '' - '' |
+---------+
| 0 |
+---------+
1 row in set (0.00 sec)
To be more clear I am adding following example (I feels will be helpful to you):
How conversion happen:
mysql> SELECT '0' = 0
-> ;
+---------+
| '0' = 0 |
+---------+
| 1 |
+---------+
1 row in set (0.00 sec)
notice its conversion:
mysql> SELECT '' = '0'
-> ;
+----------+
| '' = '0' |
+----------+
| 0 |
+----------+
1 row in set (0.00 sec)
'' converted into 0, '0' converted into 0 but '' not equals to '0'
mysql> SELECT '1' = 1
-> ;
+---------+
| '1' = 1 |
+---------+
| 1 |
+---------+
1 row in set (0.00 sec)
mysql> SELECT '' = 1
-> ;
+--------+
| '' = 1 |
+--------+
| 0 |
+--------+
1 row in set (0.00 sec)

I'd explain select ''-'', which is the same as select '' - '', as select cast('' as int) - cast('' as int) which is select 0-0..
With select '-' you just get a string. Hope that makes sense...

'' is an empty string; - is subtraction. So you're subtracting one empty string from another. Subtraction is a numeric operator, so its result is a number, and mysql converts its arguments into numbers before subtracting them. The numeric value of '' is zero — but it doesn't matter very much, since any number subtracted from itself is going to give zero anyway.

Related

mysql cast large number to char

English is not my native language; please excuse typing errors.
Im using 5.5.38-MariaDB.
Mysql statement:
SELECT CAST(11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
AS char);
I get result is 99999999999999999999999999999999999999999999999999999999999999999,why?
Update:
MariaDB [(none)]> SELECT CAST(199999999999999999999999999999999999999999999999999999999999999999999999999999999 AS char);
+-------------------------------------------------------------------------------------------------+
| CAST(199999999999999999999999999999999999999999999999999999999999999999999999999999999 AS char) |
+-------------------------------------------------------------------------------------------------+
| 199999999999999999999999999999999999999999999999999999999999999999999999999999999 |
+-------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
MariaDB [(none)]> SELECT CAST(1999999999999999999999999999999999999999999999999999999999999999999999999999999999 AS char);
+--------------------------------------------------------------------------------------------------+
| CAST(1999999999999999999999999999999999999999999999999999999999999999999999999999999999 AS char) |
+--------------------------------------------------------------------------------------------------+
| 99999999999999999999999999999999999999999999999999999999999999999 |
+--------------------------------------------------------------------------------------------------+
1 row in set, 1 warning (0.01 sec)
MariaDB [(none)]> SHOW WARNINGS;
+---------+------+--------------------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------------------+
| Warning | 1916 | Got overflow when converting '' to DECIMAL. Value truncated. |
+---------+------+--------------------------------------------------------------+
1 row in set (0.00 sec)
The 1111... is parsed as a number, specifically as DECIMAL(65, ...). 65 is the max; since the thing is bigger than that, it gave you 65 9's. And it gave you a warning (that was probably ignored):
mysql> SELECT CAST(11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 AS CHAR) AS too_big;
+-------------------------------------------------------------------+
| too_big |
+-------------------------------------------------------------------+
| 99999999999999999999999999999999999999999999999999999999999999999 |
+-------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+---------+------+---------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------+
| Warning | 1292 | Truncated incorrect DECIMAL value: '' |
+---------+------+---------------------------------------+
1 row in set (0.00 sec)
What were you hoping to get?

MySQL MIN & MAX on alpha numeric column

Simple MAX query:
SELECT MAX(Group) FROM acme
Works fine on a numeric column.
Is it possible to use to this on an alpha-numeric column and ignore anything other than a number?
yes if you cast it before use like this
mysql> SELECT MAX(CAST("123" AS UNSIGNED));
+------------------------------+
| MAX(CAST("123" AS UNSIGNED)) |
+------------------------------+
| 123 |
+------------------------------+
1 row in set (0.00 sec)
mysql> SELECT MAX(CAST("abc" AS UNSIGNED));
+------------------------------+
| MAX(CAST("abc" AS UNSIGNED)) |
+------------------------------+
| 0 |
+------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SELECT MAX(CAST("-123" AS SIGNED));
+-----------------------------+
| MAX(CAST("-123" AS SIGNED)) |
+-----------------------------+
| -123 |
+-----------------------------+
1 row in set (0.00 sec)
replace your string column name with "abc" and modify query acording to your requirment

Add float type field in Sql update query

i am using below query for update value
UPDATE cfbnv_rg_lead_detail SET value='Address' WHERE lead_id='175' && form_id='1' && CAST(field_number AS DECIMAL) = CAST(4.2 AS DECIMAL).
this query working but it also update value where field_number = 4.3 and field_number = 4.4 .
field_number field type is float.
did I do wrong?
Thanks
Ballu
You are casting to DECIMAL, which has no decimal.
You need to add (M,D) to DECIMAL(M,D).
mysql> select CAST(4.3 AS DECIMAL);
+----------------------+
| CAST(4.3 AS DECIMAL) |
+----------------------+
| 4 |
+----------------------+
1 row in set (0.00 sec)
mysql> select CAST(4.3 AS DECIMAL(10,5));
+----------------------------+
| CAST(4.3 AS DECIMAL(10,5)) |
+----------------------------+
| 4.30000 |
+----------------------------+
1 row in set (0.00 sec)
mysql> select CAST(4.3 AS DECIMAL(10,5)) = CAST(4.2 AS DECIMAL(10,5));
+---------------------------------------------------------+
| CAST(4.3 AS DECIMAL(10,5)) = CAST(4.2 AS DECIMAL(10,5)) |
+---------------------------------------------------------+
| 0 |
+---------------------------------------------------------+
1 row in set (0.00 sec)
-- Add some decimal
UPDATE cfbnv_rg_lead_detail SET value='Address' WHERE lead_id='175' && form_id='1' && CAST(field_number AS DECIMAL(10,5)) = CAST(4.2 AS DECIMAL(10,5)).

What is the true range of possible values of a field type 'DATE'?

DATE field type has limitations '1000-01-01' -'9999-12-31'.
BUT Why inserted '987-10-10' not '1000-01-01' ?
mysql> INSERT INTO DATE12(datas) VALUES('987-10-10');
Query OK, 1 row affected (0.03 sec)
mysql> SELECT * FROM DATE12;
+------+------------+
| id | datas |
+------+------------+
| NULL | 1987-11-04 |
| NULL | 0987-10-10 |
+------+------------+
2 rows in set (0.00 sec)
incorrect data format
mysql> INSERT INTO DATE12(datas) VALUES('10001-13-12');
Query OK, 1 row affected, 1 warning (0.03 sec)
mysql> SELECT * FROM DATE12;
+------+------------+
| id | datas |
+------+------------+
| NULL | 1987-11-04 |
| NULL | 0987-10-10 |
| NULL | 0000-00-00 |
But for time type all good
mysql> INSERT INTO time1(t) VALUE('-1112:45:12');
Query OK, 1 row affected, 1 warning (0.02 sec)
mysql> SELECT * FROM time1;
+------+------------+
| id | t |
+------+------------+
| NULL | NULL |
| NULL | -12:45:12 |
| NULL | -838:59:59 |
+------+------------+
3 rows in set (0.00 sec)
mysql> INSERT INTO time1(t) VALUE('11112:45:12');
Query OK, 1 row affected, 1 warning (0.02 sec)
mysql> SELECT * FROM time1;
+------+------------+
| id | t |
+------+------------+
| NULL | NULL |
| NULL | -12:45:12 |
| NULL | -838:59:59 |
| NULL | 838:59:59 |
+------+------------+
4 rows in set (0.00 sec)
mysql>
...Why insered '987-10-10' not '1000-01-01' ?
As per documentation on The DATE, DATETIME, and TIMESTAMP Types
For the DATE and DATETIME range descriptions, “supported” means that although earlier values might work, there is no guarantee.
Meaning, the dates prior to '1000-01-01' may also be accepted, but not guaranteed.
And hence, in your case the date entry '987-10-10' is accepted with no errors.
And you claim that '1000-01-01' is not inserted. But you actually tried '10001-13-12'.
And even if you try with '1000-13-12', it will fail, because, value '13' for 'month' part is meaning less.
As per documentation on Date and Time Literals
As a string with no delimiters in either 'YYYYMMDD' or 'YYMMDD' format, provided that the string makes sense as a date. For example, '20070523' and '070523' are interpreted as '2007-05-23', but '071332' is illegal (it has nonsensical month and day parts) and becomes '0000-00-00'.
Though not seen in the documentation, the above statement is also valid for format like 'YYYY-MM-DD' and others. And the same is shown in the following example:
mysql> insert into vdt(dt) values( '1001-13-32' );
ERROR 1292 (22007): Incorrect date value: '1001-13-32' for column 'dt' at row 1
mysql> select date_format( '2013-13-32', '%Y-%m-%d' ); show warnings;
+-----------------------------------------+
| date_format( '2013-13-32', '%Y-%m-%d' ) |
+-----------------------------------------+
| NULL |
+-----------------------------------------+
1 row in set, 1 warning (0.00 sec)
+---------+------+----------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------+
| Warning | 1292 | Incorrect datetime value: '2013-13-32' |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)
mysql> select str_to_date( '20131232', '%Y%m%d' ); show warnings;
+-------------------------------------+
| str_to_date( '20131232', '%Y%m%d' ) |
+-------------------------------------+
| NULL |
+-------------------------------------+
1 row in set, 1 warning (0.00 sec)
+---------+------+---------------------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------------------+
| Warning | 1411 | Incorrect datetime value: '20131232' for function str_to_date |
+---------+------+---------------------------------------------------------------+

Comparing strings with one having empty spaces before while the other does not

If I have to find a string name "Akito" and it lies in the table foo then following is the normal procedure,
select * from foo where `name = 'Akito'`
I tried to check two variations of it,
Worked fine
select * from foo where name = 'Akito '
Did not Worked Fine
select * from foo where name = ' Akito'
Can anyone please explain why did the 2nd one did not work?
Thanks in advance
CHAR types fill the string to the length of the field with null bytes (while VARCHAR add delimiters to indicate the end of the string - thus ignoring extra data at the end (I mean empty bytes)), and therefore comparisons that have spaces at the end will ignore those. Leading spaces are relevant as their alter the string itself. See Christopher's answer.
EDIT: some further elaboration required
See some practical tests below. VARCHAR types do add spaces to the string, whilst CHAR fields, even though they fill the string up to its size with spaces, ignore them during comparisons. See specifically the second line with the LENGTH function query:
mysql> create table test (a VARCHAR(10), b CHAR(10));
Query OK, 0 rows affected (0.17 sec)
mysql> insert into test values ('a', 'a'), ('a ', 'a '), (' a', ' a');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select a, LENGTH(a), b, LENGTH(b) FROM test;
+------+-----------+------+-----------+
| a | LENGTH(a) | b | LENGTH(b) |
+------+-----------+------+-----------+
| a | 1 | a | 1 |
| a | 2 | a | 1 |
| a | 2 | a | 2 |
+------+-----------+------+-----------+
3 rows in set (0.00 sec)
where MySQL states the CHAR field, with the value of 'a ' as it was inserted, has only 1 character in length. Furthermore, if we concatenate a little data:
mysql> select CONCAT(a, '.'), CONCAT(b, '.') FROM test;
+----------------+----------------+
| CONCAT(a, '.') | CONCAT(b, '.') |
+----------------+----------------+
| a. | a. |
| a . | a. |
| a. | a. |
+----------------+----------------+
3 rows in set (0.00 sec)
mysql> select CONCAT(a, b), CONCAT(b, a) FROM test;
+--------------+--------------+
| CONCAT(a, b) | CONCAT(b, a) |
+--------------+--------------+
| aa | aa |
| a a | aa |
| a a | a a |
+--------------+--------------+
3 rows in set (0.00 sec)
you can see that, since VARCHAR does store where the string ends, the space remains on concatenations - which does not hold true for CHAR types. Now, keeping in mind the previous LENGTH example, where line two has different lengths for its fields a and b, we test:
mysql> SELECT * FROM test WHERE a=b;
+------+------+
| a | b |
+------+------+
| a | a |
| a | a |
| a | a |
+------+------+
3 rows in set (0.00 sec)
Therefore, we can sum up stating that the CHAR datatype ignores and trims extra space at the end of its string, while VARCHAR does not - except during comparisons:
mysql> select a from test where a = 'a ';
+------+
| a |
+------+
| a |
| a |
+------+
2 rows in set (0.00 sec)
mysql> select a from test where a = 'a';
+------+
| a |
+------+
| a |
| a |
+------+
2 rows in set (0.00 sec)
mysql> select a from test where a = ' a';
+------+
| a |
+------+
| a |
+------+
1 row in set (0.00 sec)
So, is the same true for the CHAR type?
mysql> select a from test where b = 'a ';
+------+
| a |
+------+
| a |
| a |
+------+
2 rows in set (0.00 sec)
mysql> select a from test where b = 'a';
+------+
| a |
+------+
| a |
| a |
+------+
2 rows in set (0.00 sec)
mysql> select a from test where b = ' a';
+------+
| a |
+------+
| a |
+------+
1 row in set (0.00 sec)
Which displays that the CHAR and VARCHAR types have different storage methods, but follow the same rules for sheer string comparison. Trailing spaces are ignored; while leading spaces modify the string itself.
http://dev.mysql.com/doc/refman/5.0/en/string-comparison-functions.html says the following:
In particular, trailing spaces are significant, which is not true for
CHAR or VARCHAR comparisons performed with the = operator:
mysql> SELECT 'a' = 'a ', 'a' LIKE 'a ';
+------------+---------------+
| 'a' = 'a ' | 'a' LIKE 'a ' |
+------------+---------------+
| 1 | 0 |
+------------+---------------+
1 row in set (0.00 sec)
Trailing means not leading. Those seem to be relevant.