Skip to content

Commit 8da22b0

Browse files
authored
Fix bit type (#287)
* Fix bit type * Update * Move `public const TYPE_BIT = 'bit';` into `Yiisoft\Db\Pgsql\Schema` * Test `DEFAULT '100'::bit` * Apply `Changes requested`
1 parent bfbdfe6 commit 8da22b0

File tree

5 files changed

+58
-12
lines changed

5 files changed

+58
-12
lines changed

src/ColumnSchema.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@
1414
use Yiisoft\Db\Schema\SchemaInterface;
1515

1616
use function array_walk_recursive;
17+
use function bindec;
18+
use function decbin;
1719
use function in_array;
1820
use function is_array;
21+
use function is_int;
1922
use function is_string;
2023
use function json_decode;
24+
use function str_pad;
2125
use function strtolower;
2226

2327
/**
@@ -89,6 +93,10 @@ public function dbTypecast(mixed $value): mixed
8993
return new Param($value, PDO::PARAM_LOB);
9094
}
9195

96+
if (is_int($value) && $this->getType() === Schema::TYPE_BIT) {
97+
return str_pad(decbin($value), $this->getSize() ?? 0, '0', STR_PAD_LEFT);
98+
}
99+
92100
return $this->typecast($value);
93101
}
94102

@@ -137,6 +145,8 @@ protected function phpTypecastValue(mixed $value): mixed
137145
}
138146

139147
switch ($this->getType()) {
148+
case Schema::TYPE_BIT:
149+
return is_string($value) ? bindec($value) : $value;
140150
case SchemaInterface::TYPE_BOOLEAN:
141151
/** @psalm-var mixed $value */
142152
$value = is_string($value) ? strtolower($value) : $value;

src/Schema.php

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
use function array_merge;
2525
use function array_unique;
2626
use function array_values;
27-
use function bindec;
2827
use function explode;
2928
use function hex2bin;
3029
use function is_string;
@@ -82,6 +81,11 @@
8281
*/
8382
final class Schema extends AbstractPdoSchema
8483
{
84+
/**
85+
* Define the abstract column type as `bit`.
86+
*/
87+
public const TYPE_BIT = 'bit';
88+
8589
/**
8690
* @var array The mapping from physical column types (keys) to abstract column types (values).
8791
*
@@ -90,9 +94,9 @@ final class Schema extends AbstractPdoSchema
9094
* @psalm-var string[]
9195
*/
9296
private array $typeMap = [
93-
'bit' => self::TYPE_INTEGER,
94-
'bit varying' => self::TYPE_INTEGER,
95-
'varbit' => self::TYPE_INTEGER,
97+
'bit' => self::TYPE_BIT,
98+
'bit varying' => self::TYPE_BIT,
99+
'varbit' => self::TYPE_BIT,
96100
'bool' => self::TYPE_BOOLEAN,
97101
'boolean' => self::TYPE_BOOLEAN,
98102
'box' => self::TYPE_STRING,
@@ -790,11 +794,7 @@ protected function findColumns(TableSchemaInterface $table): bool
790794
$loadColumnSchema->defaultValue(new Expression($defaultValue));
791795
} elseif ($loadColumnSchema->getType() === 'boolean') {
792796
$loadColumnSchema->defaultValue($defaultValue === 'true');
793-
} elseif (is_string($defaultValue) && preg_match("/^B'(.*?)'::/", $defaultValue, $matches)) {
794-
$loadColumnSchema->defaultValue(bindec($matches[1]));
795-
} elseif (is_string($defaultValue) && preg_match("/^'(\d+)'::\"bit\"$/", $defaultValue, $matches)) {
796-
$loadColumnSchema->defaultValue(bindec($matches[1]));
797-
} elseif (is_string($defaultValue) && preg_match("/^'(.*?)'::/", $defaultValue, $matches)) {
797+
} elseif (is_string($defaultValue) && preg_match("/^B?'(.*?)'::/", $defaultValue, $matches)) {
798798
if ($loadColumnSchema->getType() === 'binary' && str_starts_with($matches[1], '\\x')) {
799799
$loadColumnSchema->defaultValue(hex2bin(substr($matches[1], 2)));
800800
} else {
@@ -904,6 +904,22 @@ protected function loadColumnSchema(array $info): ColumnSchemaInterface
904904
return $column;
905905
}
906906

907+
/**
908+
* Extracts the PHP type from an abstract DB type.
909+
*
910+
* @param ColumnSchemaInterface $column The column schema information.
911+
*
912+
* @return string The PHP type name.
913+
*/
914+
protected function getColumnPhpType(ColumnSchemaInterface $column): string
915+
{
916+
if ($column->getType() === self::TYPE_BIT) {
917+
return self::PHP_TYPE_INTEGER;
918+
}
919+
920+
return parent::getColumnPhpType($column);
921+
}
922+
907923
/**
908924
* Loads multiple types of constraints and returns the specified ones.
909925
*

tests/ColumnSchemaTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ public function testPhpTypeCast(): void
4848
'float_col' => 1.234,
4949
'blob_col' => "\x10\x11\x12",
5050
'bool_col' => false,
51+
'bit_col' => 0b0110_0100, // 100
52+
'varbit_col' => 0b1_1100_1000, // 456
5153
'bigint_col' => 9_223_372_036_854_775_806,
5254
'intarray_col' => [1, -2, null, '42'],
5355
'numericarray_col' => [1.2, -2.2, null],
@@ -68,6 +70,8 @@ public function testPhpTypeCast(): void
6870
$floatColPhpTypeCast = $tableSchema->getColumn('float_col')?->phpTypecast($query['float_col']);
6971
$blobColPhpTypeCast = $tableSchema->getColumn('blob_col')?->phpTypecast($query['blob_col']);
7072
$boolColPhpTypeCast = $tableSchema->getColumn('bool_col')?->phpTypecast($query['bool_col']);
73+
$bitColPhpTypeCast = $tableSchema->getColumn('bit_col')?->phpTypecast($query['bit_col']);
74+
$varbitColPhpTypeCast = $tableSchema->getColumn('varbit_col')?->phpTypecast($query['varbit_col']);
7175
$numericColPhpTypeCast = $tableSchema->getColumn('numeric_col')?->phpTypecast($query['numeric_col']);
7276
$intArrayColPhpType = $tableSchema->getColumn('intarray_col')?->phpTypecast($query['intarray_col']);
7377
$numericArrayColPhpTypeCast = $tableSchema->getColumn('numericarray_col')?->phpTypecast($query['numericarray_col']);
@@ -82,6 +86,8 @@ public function testPhpTypeCast(): void
8286
$this->assertSame(1.234, $floatColPhpTypeCast);
8387
$this->assertSame("\x10\x11\x12", stream_get_contents($blobColPhpTypeCast));
8488
$this->assertFalse($boolColPhpTypeCast);
89+
$this->assertSame(0b0110_0100, $bitColPhpTypeCast);
90+
$this->assertSame(0b1_1100_1000, $varbitColPhpTypeCast);
8591
$this->assertSame(33.22, $numericColPhpTypeCast);
8692
$this->assertSame([1, -2, null, 42], $intArrayColPhpType);
8793
$this->assertSame([1.2, -2.2, null], $numericArrayColPhpTypeCast);

tests/Provider/SchemaProvider.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ public static function columns(): array
209209
'defaultValue' => new Expression('now()'),
210210
],
211211
'bit_col' => [
212-
'type' => 'integer',
212+
'type' => 'bit',
213213
'dbType' => 'bit',
214214
'phpType' => 'integer',
215215
'primaryKey' => false,
@@ -219,7 +219,20 @@ public static function columns(): array
219219
'size' => 8,
220220
'precision' => null,
221221
'scale' => null,
222-
'defaultValue' => 130, //b '10000010'
222+
'defaultValue' => 0b1000_0010, // 130
223+
],
224+
'varbit_col' => [
225+
'type' => 'bit',
226+
'dbType' => 'varbit',
227+
'phpType' => 'integer',
228+
'primaryKey' => false,
229+
'allowNull' => false,
230+
'autoIncrement' => false,
231+
'enumValues' => null,
232+
'size' => null,
233+
'precision' => null,
234+
'scale' => null,
235+
'defaultValue' => 0b100, // 4
223236
],
224237
'bigint_col' => [
225238
'type' => 'bigint',

tests/Support/Fixture/pgsql.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ CREATE TABLE "type" (
152152
bool_col boolean NOT NULL,
153153
bool_col2 boolean DEFAULT TRUE,
154154
ts_default TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
155-
bit_col BIT(8) NOT NULL DEFAULT B'10000010',
155+
bit_col BIT(8) NOT NULL DEFAULT B'10000010', -- 130
156+
varbit_col VARBIT NOT NULL DEFAULT '100'::bit, -- 4
156157
bigint_col BIGINT,
157158
intarray_col integer[],
158159
numericarray_col numeric(5,2)[],

0 commit comments

Comments
 (0)