Skip to content

Commit

Permalink
feat(Spanner): float 32 support (#7080)
Browse files Browse the repository at this point in the history
  • Loading branch information
vishwarajanand committed Mar 28, 2024
1 parent 38be7f9 commit 8d3c0fd
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 147 deletions.
1 change: 1 addition & 0 deletions Spanner/src/Database.php
Expand Up @@ -110,6 +110,7 @@ class Database

const TYPE_BOOL = TypeCode::BOOL;
const TYPE_INT64 = TypeCode::INT64;
const TYPE_FLOAT32 = TypeCode::FLOAT32;
const TYPE_FLOAT64 = TypeCode::FLOAT64;
const TYPE_TIMESTAMP = TypeCode::TIMESTAMP;
const TYPE_DATE = TypeCode::DATE;
Expand Down
9 changes: 7 additions & 2 deletions Spanner/src/ValueMapper.php
Expand Up @@ -33,6 +33,7 @@ class ValueMapper

const TYPE_BOOL = TypeCode::BOOL;
const TYPE_INT64 = TypeCode::INT64;
const TYPE_FLOAT32 = TypeCode::FLOAT32;
const TYPE_FLOAT64 = TypeCode::FLOAT64;
const TYPE_TIMESTAMP = TypeCode::TIMESTAMP;
const TYPE_DATE = TypeCode::DATE;
Expand All @@ -47,6 +48,7 @@ class ValueMapper

/**
* @var array
* @internal
*/
public static $allowedTypes = [
self::TYPE_BOOL,
Expand All @@ -62,6 +64,7 @@ class ValueMapper
self::TYPE_JSON,
self::TYPE_PG_NUMERIC,
self::TYPE_PG_JSONB,
self::TYPE_FLOAT32,
];

/*
Expand Down Expand Up @@ -324,6 +327,7 @@ private function decodeValue($value, array $type)
}
break;

case self::TYPE_FLOAT32:
case self::TYPE_FLOAT64:
// NaN, Infinite and -Infinite are possible FLOAT64 values,
// but when the gRPC response is decoded, they are represented
Expand All @@ -346,8 +350,9 @@ private function decodeValue($value, array $type)

default:
throw new \RuntimeException(sprintf(
'Unexpected string value %s encountered in FLOAT64 field.',
$value
'Unexpected string value %s encountered in %s field.',
$value,
TypeCode::name($type['code'])
));
}
}
Expand Down
47 changes: 38 additions & 9 deletions Spanner/tests/System/PgQueryTest.php
Expand Up @@ -55,6 +55,7 @@ public static function setUpBeforeClass(): void
created_at timestamptz,
dt date,
data jsonb,
weight float4,
PRIMARY KEY (id)
)'
)->pollUntilComplete();
Expand All @@ -71,7 +72,8 @@ public static function setUpBeforeClass(): void
'bytes_col' => new Bytes('hello'),
'created_at' => self::$timestampVal,
'data' => '{"a": "hello", "b": "world"}',
'dt' => '2020-01-01'
'dt' => '2020-01-01',
'weight' => 1.432
],
[
'id' => 2,
Expand All @@ -81,7 +83,8 @@ public static function setUpBeforeClass(): void
'age' => 26,
'created_at' => self::$timestampVal,
'data' => '{}',
'dt' => '2021-01-01'
'dt' => '2021-01-01',
'weight' => 1.234
]
]);
}
Expand Down Expand Up @@ -200,32 +203,56 @@ public function testBindFloat64Parameter()
$this->assertCount(2, iterator_to_array($res));
}

public function testBindFloat64ParameterNull()
public function testBindFloat32Parameter()
{
$db = self::$database;

$res = $db->execute('SELECT * FROM ' . self::TABLE_NAME . ' WHERE weight = $1', [
'parameters' => [
'p1' => 1.234
],
'types' => [
'p1' => Database::TYPE_FLOAT32
]
]);

$this->assertCount(1, iterator_to_array($res));
}

public function testBindFloatParameterNull()
{
$res = self::$database->execute('SELECT * FROM ' . self::TABLE_NAME . ' WHERE rating IS NULL');
$currentFloat64NullCount = count(iterator_to_array($res));
$res = self::$database->execute('SELECT * FROM ' . self::TABLE_NAME . ' WHERE weight IS NULL');
$currentFloat32NullCount = count(iterator_to_array($res));
// insert a value with a float param binded to null
self::$database->runTransaction(function (Transaction $t) {
$t->executeUpdate(
'INSERT INTO ' . self::TABLE_NAME . '(id, name, registered, rating, age) '
. 'VALUES($1, $2, $3, $4, $5)',
'INSERT INTO ' . self::TABLE_NAME . '(id, name, registered, rating, age, weight) '
. 'VALUES($1, $2, $3, $4, $5, $6)',
[
'parameters' => [
'p1' => 5,
'p2' => 'Vince',
'p3' => true,
'p4' => null,
'p5' => 26
'p5' => 26,
'p6' => null
],
'types' => [
'p4' => Database::TYPE_FLOAT64
'p4' => Database::TYPE_FLOAT64,
'p6' => Database::TYPE_FLOAT32
]
]
);
$t->commit();
});

$res = self::$database->execute('SELECT * FROM ' . self::TABLE_NAME . ' WHERE rating IS NULL');
$resFloat64NullCount = self::$database->execute('SELECT * FROM ' . self::TABLE_NAME . ' WHERE rating IS NULL');
$resFloat32NullCount = self::$database->execute('SELECT * FROM ' . self::TABLE_NAME . ' WHERE weight IS NULL');

$this->assertCount(1, iterator_to_array($res));
$this->assertCount(1 + $currentFloat64NullCount, iterator_to_array($resFloat64NullCount));
$this->assertCount(1 + $currentFloat32NullCount, iterator_to_array($resFloat32NullCount));
}

public function testBindStringParameter()
Expand Down Expand Up @@ -650,6 +677,7 @@ public function arrayTypesEmptyProvider()
return [
[Database::TYPE_BOOL],
[Database::TYPE_INT64],
[Database::TYPE_FLOAT32],
[Database::TYPE_FLOAT64],
[Database::TYPE_STRING],
[Database::TYPE_BYTES],
Expand Down Expand Up @@ -686,6 +714,7 @@ public function arrayTypesNullProvider()
return [
[Database::TYPE_BOOL],
[Database::TYPE_INT64],
[Database::TYPE_FLOAT32],
[Database::TYPE_FLOAT64],
[Database::TYPE_STRING],
[Database::TYPE_BYTES],
Expand Down
31 changes: 27 additions & 4 deletions Spanner/tests/System/PgWriteTest.php
Expand Up @@ -53,6 +53,7 @@ public static function setUpBeforeClass(): void
bytesfield bytea,
datefield date,
floatfield float,
float4field float4,
intfield bigint,
stringfield varchar(1024),
timestampfield timestamptz,
Expand All @@ -61,6 +62,7 @@ public static function setUpBeforeClass(): void
arrayfield bigint[],
arrayboolfield boolean[],
arrayfloatfield float[],
arrayfloat4field float4[],
arraystringfield varchar(1024)[],
arraybytesfield bytea[],
arraytimestampfield timestamptz[],
Expand All @@ -85,6 +87,9 @@ public function fieldValueProvider()
[$this->randId(), 'floatfield', 3.1415],
[$this->randId(), 'floatfield', INF],
[$this->randId(), 'floatfield', -INF],
[$this->randId(), 'float4field', 3.1415],
[$this->randId(), 'float4field', INF],
[$this->randId(), 'float4field', -INF],
[$this->randId(), 'datefield', new Date(new \DateTime('1981-01-20'))],
[$this->randId(), 'intfield', 787878787],
[$this->randId(), 'stringfield', 'foo bar'],
Expand Down Expand Up @@ -115,7 +120,7 @@ public function testWriteAndReadBackValue($id, $field, $value)
if ($value instanceof Timestamp) {
$this->assertEquals($value->formatAsString(), $row[$field]->formatAsString());
} else {
$this->assertEquals($value, $row[$field]);
$this->assertValues($value, $row[$field]);
}

// test result from executeSql
Expand All @@ -129,7 +134,7 @@ public function testWriteAndReadBackValue($id, $field, $value)
if ($value instanceof Timestamp) {
$this->assertEquals($value->formatAsString(), $row[$field]->formatAsString());
} else {
$this->assertEquals($value, $row[$field]);
$this->assertValues($value, $row[$field]);
}
}

Expand Down Expand Up @@ -242,6 +247,10 @@ public function arrayFieldValueProvider()
[$this->randId(), 'arrayfloatfield', []],
[$this->randId(), 'arrayfloatfield', [1.1, null, 1.3]],
[$this->randId(), 'arrayfloatfield', null],
[$this->randId(), 'arrayfloat4field', [1.1, 1.2, 1.3]],
[$this->randId(), 'arrayfloat4field', []],
[$this->randId(), 'arrayfloat4field', [1.1, null, 1.3]],
[$this->randId(), 'arrayfloat4field', null],
[$this->randId(), 'arraystringfield', ['foo','bar','baz']],
[$this->randId(), 'arraystringfield', []],
[$this->randId(), 'arraystringfield', ['foo',null,'baz']],
Expand Down Expand Up @@ -276,7 +285,7 @@ public function testWriteAndReadBackArrayValue($id, $field, $value)
$read = $db->read(self::TABLE_NAME, $keyset, [$field]);
$row = $read->rows()->current();

$this->assertEquals($value, $row[$field]);
$this->assertValues($value, $row[$field]);

// test result from executeSql
$exec = $db->execute(sprintf('SELECT %s FROM %s WHERE id = $1', $field, self::TABLE_NAME), [
Expand All @@ -290,7 +299,7 @@ public function testWriteAndReadBackArrayValue($id, $field, $value)
if ($value instanceof Bytes) {
$this->assertEquals($value->formatAsString(), $row[$field]->formatAsString());
} else {
$this->assertEquals($value, $row[$field]);
$this->assertValues($value, $row[$field]);
}
}

Expand Down Expand Up @@ -1107,4 +1116,18 @@ public function testExecuteUpdateBatchMultipleErrors()
$this->assertEquals(Code::INVALID_ARGUMENT, $res->error()['status']['code']);
$this->assertEquals($statements[2], $res->error()['statement']);
}

private function assertValues($expected, $actual, $delta = 0.000001)
{
if (is_float($expected)) {
$this->assertEqualsWithDelta($expected, $actual, $delta);
} elseif (is_array($expected)) {
$this->assertCount(count($expected), $actual);
foreach ($expected as $key => $value) {
$this->assertValues($value, $actual[$key]);
}
} else {
$this->assertEquals($expected, $actual);
}
}
}

0 comments on commit 8d3c0fd

Please sign in to comment.