peachpiecompiler / peachpie

PeachPie - the PHP compiler and runtime for .NET and .NET Core
https://www.peachpie.io
Apache License 2.0
2.31k stars 201 forks source link

Peachpie.Library.PDO.MySQL convert MySQL `tinyint` value to `int` error. #1103

Closed jameschung2000 closed 1 year ago

jameschung2000 commented 1 year ago

I am testing the MYSQL tinyint data type on Peachpie.NET.Sdk/1.1.5 via Peachpie.Library.PDO.MySQL/1.1.5 and find out the operattor == return error results. To reproduce it, please follow the steps listed below:

  1. Create a table with tinyint data type in MySQL db, and insert value 5 to the field address_type:
CREATE TABLE test_data (
   address_type tinyint,
   address varchar(255)
);

INSERT INTO test_data VALUES (5, "Testing Road");
  1. Run the following PHP code on PHP7 and Peachpie .NET environment respectively, and check the results:
<?php

use PDO;

$dbms='mysql';   
$host='127.0.0.1'; 
$dbName='test_data'; 
$user='root';     
$pass='test123456';  
$dsn="$dbms:host=$host;dbname=$dbName";

$query = 'select * from `test_data` limit 1';

try {
    $dbh = new PDO($dsn, $user, $pass); //Initialize PDO
    $dbh->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
    echo "DB connected<br/>\n";

    $statement = $dbh->prepare($query);
    $statement->execute();

    $result = $statement->fetchAll(PDO::FETCH_OBJ)[0];
    print_r($result);
    echo "<br>\n";

    echo "address_type:".$result->address_type."<br>\n";

    echo "address_type intval:".intval($result->address_type)."<br>\n";

    if ($result->address_type == 5)
    {
        echo "address_type is 5<br>\n";
    }
    else {
        echo "address_type is not 5<br>\n";
    }

} catch (PDOException $e) {
    die ("Error!: " . $e->getMessage() . "<br/>");
}

On PHP environment, it produces the correct result as expected, the address_type value is 5:

DB connected
stdClass Object
(
    [address_type] => 5
    [address] => Testing Road
)
address_type:5
address_type intval:5
address_type is 5

However, on Peachpie .NET, it produces incorrect results, the address_type int value is 1:

DB connected
stdClass Object ( [address_type] => System\SByte Object ( [m_value:System\SByte:private] => 5 ) [address] => Testing Road )
address_type:5
address_type intval:1
address_type is not 5

It is because the MySQL TinyInt is loaded as System\SByte in Peachpie PDO, however the conversion from SByte to int is not supported in Peachpie runtime (Peachpie.Runtime/Conversions.cs line 542):

        public static long ToLong(object obj)
        {
            if (obj is IPhpConvertible convertible)
            {
                return convertible.ToLong();
            }
            else if (obj is decimal d)
            {
                // boxed System.Decimal
                return (long)d;
            }
            else
            {
                PhpException.Throw(PhpError.Notice, string.Format(Resources.ErrResources.object_could_not_be_converted, PhpVariable.GetClassName(obj), PhpVariable.TypeNameInt));
                return ReferenceEquals(obj, null) ? 0 : 1;
            }
        }

It causes lots of trouble for converting history PHP codes to Peachpie, could you please help to fix the errors in the coming version, or provide a way to bypass the issues?

jakubmisek commented 1 year ago

@jameschung2000 thank you for reporting the issue, and fixing it!

Indeed, the root of the problem was the incomplete PhpValue.FromClr()