In SQL, can't set a binary to 1 - php

I have created a table in MySQL with a binary field name 'active' and set to NULL by default.
But when I want to update it with this command:
$update_users = $bdd -> query("UPDATE users SET `active` = 1 WHERE `id` = '$data1' LIMIT 1") or die(mysql_error());
The field is updated to 31 ! and not to 1.
I have also tried
SET `active` = true
but same result.
p.s: I have set 'active' using phpMyAdmin interface (no SQL statement), but here are the values of this field: Type => binary(1), Null => yes, Defaut => NULL

0x31 == 49 is the ASCII code of character '1'.
The value is stored in the column but, because of its type, it is returned in a special format: each byte from the value is displayed in its hexadecimal representation (2 uppercase hex digits). Depending on the MySQL client you use, the 0x hexadecimal prefix may or may not be present in the output.
As the documentation explains, the BINARY type contains strings (similar to CHAR types). That's why the numeric value you want to insert (1) is handled as a string and it becomes the character '1').
In order to store the number 1 into a BINARY column you have to store the character '0x01' in it:
UPDATE users SET `active` = 0x01 WHERE `id` = '$data1' LIMIT 1
Or you better use the TINYINT type instead.

I think you are confusing BINARY. According to the documentation:
The BINARY and VARBINARY types are similar to CHAR and VARCHAR, except that they contain binary strings rather than nonbinary strings. That is, they contain byte strings rather than character strings. This means they have the binary character set and collation, and comparison and sorting are based on the numeric values of the bytes in the values.
From looking at your question I assume what you really want is something like a boolean value (0 or 1) and not binary data.
In this case either use TINYINT(1) or BIT(1).

Related

How to get the character set from a resultset?

mysqli_result::fetch_field() returns a type property for each column, which is an integer value.
The integer value is the same for VARCHAR and VARBINARY (0xFD) columns and also for CHAR and BINARY (0xFE) columns. Those column types can be detected with MYSQLI_TYPE_STRING and MYSQLI_TYPE_VAR_STRING constants.
To know if a string column is BINARY (they have a collation called binary), or to know if columns need to be converted to another character set, the character set name is really needed.
But... mysqli_result::fetch_field() has a charsetnr property which again returns an integer for the character set. Only this time there seems to be no way of knowing the character set name, let alone the collation?
So how can one get the character set names from mysqli_result ?
You do not need to know character set to see whether the field is binary.
Consider this example:
if ($result = $mysqli->query($query)) {
/* Get field information for all columns */
$finfo = $result->fetch_fields();
foreach ($finfo as $val) {
printf("Name: %s\n", $val->name);
printf("Table: %s\n", $val->table);
printf("Max. Len: %d\n", $val->max_length);
printf("Length: %d\n", $val->length);
printf("charsetnr: %d\n", $val->charsetnr);
printf("Flags: %d\n", $val->flags);
printf("Type: %d\n\n", $val->type);
}
$result->free();
}
You have $field->flags property. Check it for bit 128 (0x80). If the bit is set then the field is binary (BINARY, VARBINARY) and has "binary" collation.
I am not sure that you can set "binary" collation on non-binary field.
TL;DR charsetnr is the ID of the collation as listed by SHOW COLLATION.
I couldn't help noticing that even for numeric columns charsetnr was set to 63. This pointed me towards the manual that says:
To distinguish between binary and nonbinary data for string data types, check whether the charsetnr value is 63. If so, the character set is binary, which indicates binary rather than nonbinary data. This enables you to distinguish BINARY from CHAR, VARBINARY from VARCHAR, and the BLOB types from the TEXT types.
Retrieve more information about the collation and character set via:
SELECT `COLLATION_NAME`
, `CHARACTER_SET_NAME`
, `IS_DEFAULT`
, `IS_COMPILED`
, `SORTLEN`
FROM `INFORMATION_SCHEMA`.`COLLATIONS`
WHERE `ID` = ?;
SELECT IFNULL(COLLATION_NAME, 'binary')
FROM `COLUMNS`
WHERE table_schema = 'biglim'
AND table_name = 'article'
will find the collation associated with a particular table in a particular database (schema).

How to check if bit is set in MySQL

I have a table in a MySQL database with a BIT(64) row, which is a bitmask of 64 flags.
Using PHP and mysqli, I have an integer $n, which is in the range [0, 64). I have already written a function (see Appendix I) to set the nth bit of a byte array (i.e. string in PHP).
When passing the abovementioned byte-array (string) to MySQL, it seems that bitmask & ?, where ? is mysqli::bind_paramed as the byte array (param type is "s"), does not compare the bits as expected.
For example, using this query:
SELECT id FROM my_table WHERE (bitmask & ?) > 0
upon this table:
CREATE TABLE my_table (id INT PRIMARY KEY, bitmask BIT(64));
How can this be fixed?
I thought of passing a bin2hex and UNHEX() it, but this doesn't seem to fix the problem.
Appendix I
public static function setNthBit(int $n, int $bytes = 8) : string{
$offset = $n >> 3;
$byteArray = str_repeat("\0", $bytes);
$byteArray{$bytes - 1 - $offset} = chr(1 << ($n & 7));
return $byteArray;
}
It appears that the problem originates from that MySQL does not support bitwise comparison of strings. When I pass the bitmask as the parameter directly, MySQL would try to interpret as an integer, e.g. trying to interpret bitmask & '123' as bitmask & 123. I'm unsure how MySQL interprets a bunch of binary characters like \xFF or \x00 -- it just won't work, probably interpreted as 0.
I solved this by passing the bin2hex of the bitmask in the input and then CONV(?, 16, 10) in the query. CONV() will express the data in decimal, which MySQL will interpret as, hopefully, something like a BIGINT, which can be successfully bitwise-compared with a BIT(64) row.

Not receiving correct data from firebird database when using PHP

I have some very odd situation. I am making a query to a firebird database and there is mismatch with the result in PHP. In DB the result is just fine, but when it comes to PHP there are different values.
The query:
SELECT LIST(t."ID", ',') ID,t."Date", LIST(n."Name",',') Name
FROM "Tests" t
LEFT JOIN "Names of tests" n ON t."Name ID" = n."ID"
WHERE t."Locked" = 0
GROUP BY t."Date"
ORDER BY t."Date" DESC
Result in DB:
ID = 546,552 Date = 23.10.2015 Name = Математика (тест),География(тест)
Result in PHP:
ID => 0x0000000200000000,
Date => 2015-10-23,
Name => 0x0000000500000000
I am using "UTF-8" encoding when connecting to DB with ibase_connect() the database encoding is WIN1251.
The result type of LIST() is a blob, not a CHAR or VARCHAR. I don't use PHP myself, but I believe that the Firebird/Interbase driver for PHP requires you to explicitly request the blob.
The values you see for ID and Name are the blob ids that can be used to request the blobs.
You have two options:
Request the blob value using these blob ids, see ibase_blob_open and ibase_blob_get (afaik, you will need to do the correct byte to character conversion yourself)
Cast the value to a VARCHAR (eg CAST(LIST(t."ID", ',') AS VARCHAR(2048)) AS ID)
The downside of the second option is that if you can have really long results, then you also need to cast to a long VARCHAR, otherwise you get truncation errors; and unfortunately varchars are restricted to 32K-2 bytes (8191 characters for UTF8), and a row as a whole to 64K bytes.

MD5 Hashes not matching

I am trying to match a md5 has (generated through php) to its original value in a SQLExpress database.
I am using the following function in my SQL query
master.sys.fn_varbintohexsubstring(0, HASHBYTES('MD5', 'ID'), 1, 0)
Where 'ID' is the field in the database.
However they both seem to return different values for the md5 hash. I have been using '12290' as a static value to test this.
php md5() returns: 0bd81786a8ec6ae9b22cbb3cb4d88179
The following SQL Statement returns the same output:
DECLARE #password VARCHAR(255)
SET #password = master.sys.fn_varbintohexsubstring(0, HASHBYTES('MD5', '12290'), 1, 0)
SELECT #password
Yet when I run the following statement from the table:
SELECT ID, master.sys.fn_varbintohexsubstring(0, HASHBYTES('MD5', CONVERT(NVARCHAR(255), ID)), 1, 0) AS temp
FROM Clients
ORDER BY ID ASC
The 'temp' value matching to the 'ID' value of 12290 returns: 1867dce5f1ee1ddb46ff0ccd1fc58e03
Any help on the matter would be much appreciated!
Thanks
Python helped me to help you.
>>> from hashlib import md5
>>> md5('1\x002\x002\x009\x000\x00').digest().encode('hex')
'1867dce5f1ee1ddb46ff0ccd1fc58e03'
NVARCHAR is Unicode type and it seems from the above experiment that '12990' is stored as UTF-16LE in your database: '1\02\09\09\00\0'.
Assuming that the data encoding in the PHP is UTF-8 data and you don't want to change the existing data in the database, this is how you can fix your PHP script:
<?php
$password = '12290';
$hash = md5(mb_convert_encoding($password, 'UTF-16LE', 'UTF-8')) . "\n";
echo $hash;
?>
Output:
susam#swift:~$ php utf16le-hash.php
1867dce5f1ee1ddb46ff0ccd1fc58e03
In case the data in PHP is in some other encoding such as ASCII, ISO-8859-1, etc. you can change the third argument to mb_convert_encoding accordingly. The list of all supported encodings is available at: http://www.php.net/manual/en/mbstring.supported-encodings.php
Also, see http://www.php.net/manual/en/function.mb-convert-encoding.php
I don't have SQL server to test this on, but the CONVERT command might be creating the NVARCHAR with 240-odd trailing blanks (as you have specified NVARCHAR(255))
Try setting the NVARCHAR to the length of the ID to test:
ARE #password VARCHAR(255)
SET #password = master.sys.fn_varbintohexsubstring(0, HASHBYTES('MD5', CONVERT(NVARCHAR(5), '12290')), 1, 0)
SELECT #password
Try with different lengths in the CONVERT - is there any difference?
One of two things is most likely the problem:
Either the ID column in that row has a value not exactly equal to '12290' (e.g. extra whitespace)
Or the CONVERT function produces such a value
In any case, a standard debugging approach would be to use an SQL query to SELECT the string lengths of that ID field and the return value of CONVERT; if either is not equal to 5, you found the error.
Alternatively you can perform a dump of the table in question including data, and look at the generated INSERT statement to see what the database says the value in that column is.

php reading mysql bit field returning weird character

I am using mysql_fetch_assoc($query), one of the bit field returns out to be , which is supposedly to be true.
The problem is that I also need to output this to xml and it's an illegal xml character.
the charset for the db table is utf-8. why does this happen?
MySQL is literally returning 0x00 and 0x01 for the bit fields. You'll have to convert them into something appropriate either PHP-side
$bitvalue = ($bitvalue == 0x01) ? 'TRUE' : 'FALSE'
or in the query:
SELECT CAST(bitfield AS unsigned int)
FROM ...
which will convert it to an int and return as '0' and '1' (0x48 and 0x49).
Just as an aside, some of the older mysql libraries pre-date support for real bit fields in MySQL (when they were silently converted to char(1)) and will trash the values, so if you're stuck with one of those dinosaur versions, you may have to use the query version rather than the PHP-side conversion.
You can also use: ord($bitvalue).
Use the BIN function in your SELECT.
http://dev.mysql.com/doc/refman/5.0/en/bit-field-literals.html

Categories