Why this condition 0='=1' is true? - mysql

I have seen some programmers using this condition 0='"="1' and don't know why it returns true ?Can anyone explain it to me ? Thank you!

In order to compare an number with a string the string is cast to a number.
When casting a string to a number, mysql accepts all leading numbers and throws away the rest. When there are no leading numbers, the string is cast to zero:
0 = 'abc' -- true: string cast to 0
1 = '1abc' -- true: string cast to 1
Your string is evaluated as being 0 because there are no leading numbers.

The issue has no relation with "unusual" looks of the string. Yes. it's just primitive implicit type-conversion. You can do:
mysql> select 0='blablabla';
+---------------+
| 0='blablabla' |
+---------------+
| 1 |
+---------------+
1 row in set, 1 warning (0.00 sec)
And see your reason:
mysql> show warnings;
+---------+------+-----------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'blablabla' |
+---------+------+-----------------------------------------------+
1 row in set (0.00 sec)
So same with your '"="1' - it's just string and will be truncated during conversion to DOUBLE causing zero-value.

Related

Enum value is not set, BUT is not null

I have a row in a table that is an enum type, but can also be NULL by default.
Empty string ('') is not one of the possible enum value, and yet, after some time, I found out that all of the entries I thought to be null were actually set to an empty string.
Fixing this wasn't a problem. But, I'm willing to know how this could even happen in the first place, -to make sure I don't get any of these ever again,- but so far I haven't been able to recreate new entries with an empty string as value.
What could I have that would cause an enum value to be set neither to null nor any of the possible values?
If someone tries to insert a value to the enum that is not in its defined list of values, and strict mode is not enforced, then the value will be truncated to ''.
mysql> create table t (e enum('a','b','c'));
mysql> insert into t set e='d';
ERROR 1265 (01000): Data truncated for column 'e' at row 1
mysql> set session sql_mode=''; -- disable strict mode
mysql> insert into t set e='d';
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> show warnings;
+---------+------+----------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------+
| Warning | 1265 | Data truncated for column 'e' at row 1 |
+---------+------+----------------------------------------+
mysql> select * from t;
+------+
| e |
+------+
| |
+------+
https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html says:
Strict mode produces an error for attempts to create a key that exceeds the maximum key length. When strict mode is not enabled, this results in a warning and truncation of the key to the maximum key length.
It doesn't say so explicitly, but "exceeds the maximum length" also includes "not an element of the enum."

mysql converting bit to char not working

I was trying to feed a result of a query as a parameter for another query and all was working fine except this field that has a datatype of bit. so i tried to convert the value of the field using convert() and cast() but it seems to be not working as its returning this wierd symbol of a small rectange which hava three 0's and a 1. so can anyone tell me why this is happening and how to fix it , here is my query
select CONVERT(isMale , char(5)) from person;
and the thing is it gives me the correct answer when i dont use the convert but since am giving this result to another query as a parameter it causing me the problem.
you can use BIN function like this:
SELECT BIN(isMale +0) from person;
sample
MariaDB [yourschema]> SELECT BIN(b'1001' +0) ;
+-----------------+
| BIN(b'1001' +0) |
+-----------------+
| 1001 |
+-----------------+
1 row in set (0.00 sec)
MariaDB [yourschema]>
Here some stuff from MariaDB Manual:
Description
Converts numbers between different number bases. Returns a
string representation of the number N, converted from base from_base
to base to_base.
Returns NULL if any argument is NULL, or if the second or third
argument are not in the allowed range.
The argument N is interpreted as an integer, but may be specified as
an integer or a string. The minimum base is 2 and the maximum base is
36. If to_base is a negative number, N is regarded as a signed number. Otherwise, N is treated as unsigned. CONV() works with 64-bit
precision.
Some shortcuts for this function are also available: BIN(), OCT(),
HEX(), UNHEX(). Also, MariaDB allows binary literal values and
hexadecimal literal values.
BIN is a short form from CONV(value,from,to) where you can convert from base to base
so binary 1001 = 9 as int
here i give the value in decimal (14) and convert it from base 10 to base 2
MariaDB [yourschema]> SELECT CONV(14,10 ,2);
+-----------------+
| CONV(14,10 ,2) |
+-----------------+
| 1110 |
+-----------------+
1 row in set (0.00 sec)
so, if you want to have 0 on the left you can add a value like this
MariaDB [yourschema]> SELECT CONV(8192 + 14,10 ,2);
+------------------------+
| CONV(8192 + 14,10 ,2) |
+------------------------+
| 10000000001110 |
+------------------------+
1 row in set (0.00 sec)
and then you can get n chars from right:
MariaDB [yourschema]> SELECT RIGHT(CONV(8192 + 14,10 ,2),8);
+---------------------------------+
| RIGHT(CONV(8192 + 14,10 ,2),8) |
+---------------------------------+
| 00001110 |
+---------------------------------+
1 row in set (0.40 sec)
MariaDB [yourschema]>
I think you want to use CAST
select CAST(isMale as CHAR) from person;
seeing #Bernd Buffen answer i tried using the convert with +0 and it works , eventhough i dont know why
select CONVERT(isMale +0, char(5)) from person;

Save UUID as varbinary(16) in MySQL causes com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'ID' at row 1

I have a field id defined as below. It's varbinary(16) in database, when i am inserting a new record through JPA, i got "com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'ID' at row 1". What am I doing wrong?
#Id
#Column(name="ID")
private UUID id;
A UUID is a 128-bit number represented by a utf8 string of five hexadecimal numbers separated by hyphen( '-' ). Char length of the string returned by UUID() is '36'.
Hence column definition with '16' length is not sufficient. And when defined so, you will receive the said error.
mysql> create table tbl_so_q24028471_vb( v varbinary(16) );
Query OK, 0 rows affected (0.42 sec)
mysql> desc tbl_so_q24028471_vb;
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| v | varbinary(16) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
1 row in set (0.17 sec)
mysql> insert into tbl_so_q24028471_vb values( uuid() );
ERROR 1406 (22001): Data too long for column 'v' at row 1
Change the column definition to accommodate more length and use.
mysql> alter table tbl_so_q24028471_vb modify column v varbinary(36);
Query OK, 0 rows affected (0.86 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into tbl_so_q24028471_vb values( uuid() );
Query OK, 1 row affected (0.08 sec)
mysql> select * from tbl_so_q24028471_vb;
+--------------------------------------+
| v |
+--------------------------------------+
| 630d3270-ebba-11e3-bd03-bc8556a95cc2 |
+--------------------------------------+
Your trying to store a 36 character string in a 16 byte space. That's not going to work.
You need get at the bits behind the UUID, which will fit in a binary(16). Since you're using Java, you can do something like:
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return bb.array();
and then insert the resulting byte array into the DB.

strict mode to avoid type conversion

Is there any sql mode that will return an error instead of implicitly converting the string to integer?
mysql> select * from todel ;
+------+--------+
| id | name |
+------+--------+
| 1 | abc |
| 2 | xyz |
| 0 | ABCxyz |
+------+--------+
3 rows in set (0.00 sec)
I expect an error message instead of a row with id 0
mysql> select * from todel where id = 'abc';
+------+--------+
| id | name |
+------+--------+
| 0 | ABCxyz |
+------+--------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+-----------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'abc' |
+---------+------+-----------------------------------------+
1 row in set (0.01 sec)
I understand your concerns, but it's for this very reason you should never have an id set to 0. In the long run I think you should reconsider your table rows before the behavior which isn't a problem in ideal situations. I haven't found anything relevant to this through a little searches, and that's probably because it's probably not a problem unless you make it one.
Apart from that, you could read relevant column data and act accordingly in php/whatev. From the table COLUMNS in information_schema, you can filter by TABLE_SCHEMA (database), TABLE_NAME and COLUMN_NAME to get DATATYPE (double). If the column you're changing has a certain DATATYPE, let the script give error before running the MySQL query.
Another way to do it would simply be to convert input before parsing:
if ( ! is_numeric($id))
$id = 'NULL';
To prevent incorrect INSERTs or UPDATEs, you already have that mode.
In the end I can't come up with many practical ways that this strict mode you're after would benefit the MySQL users.
You can use STRICT_ALL_TABLES sql mode:
set ##GLOBAL.sql_mode = "STRICT_ALL_TABLES";
set ##SESSION.sql_mode = "STRICT_ALL_TABLES";
However it works just on write operations:
MariaDB [(none)]> insert into test.test values ( "abc", "lol" );
--------------
insert into test.test values ( "abc", "lol" )
--------------
ERROR 1366 (22007): Incorrect integer value: 'abc' for column 'id' at row 1
There is no such thing to disable implicit conversions for read queries; instead you can just check if there are warnings and if yes, just free the result, abort the statement, and threat those warnings as errors.

How can I convert a string to a float in mysql?

I have a table containing latitude and longitude values stored as strings (VARCHAR) which I'd like to convert to FLOAT (10,6).
However there doesn't appear to be a straightforward way to do this using CAST() or CONVERT().
How can I convert these columns easily? This is a one-time conversion.
It turns out I was just missing DECIMAL on the CAST() description:
DECIMAL[(M[,D])]
Converts a value to DECIMAL data type. The optional arguments M and D specify the precision (M specifies the total number of digits) and the scale (D specifies the number of digits after the decimal point) of the decimal value. The default precision is two digits after the decimal point.
Thus, the following query worked:
UPDATE table SET
latitude = CAST(old_latitude AS DECIMAL(10,6)),
longitude = CAST(old_longitude AS DECIMAL(10,6));
mysql> SELECT CAST(4 AS DECIMAL(4,3));
+-------------------------+
| CAST(4 AS DECIMAL(4,3)) |
+-------------------------+
| 4.000 |
+-------------------------+
1 row in set (0.00 sec)
mysql> SELECT CAST('4.5s' AS DECIMAL(4,3));
+------------------------------+
| CAST('4.5s' AS DECIMAL(4,3)) |
+------------------------------+
| 4.500 |
+------------------------------+
1 row in set (0.00 sec)
mysql> SELECT CAST('a4.5s' AS DECIMAL(4,3));
+-------------------------------+
| CAST('a4.5s' AS DECIMAL(4,3)) |
+-------------------------------+
| 0.000 |
+-------------------------------+
1 row in set, 1 warning (0.00 sec)
This will convert to a numeric value without the need to cast or specify length or digits:
STRING_COL+0.0
If your column is an INT, can leave off the .0 to avoid decimals:
STRING_COL+0