Skip to content

Commit bd43b35

Browse files
authored
Merge pull request #9 from litebase/fix-blob-and-float-support
Fix BLOB and FLOAT support
2 parents 3115551 + 18ee188 commit bd43b35

3 files changed

Lines changed: 118 additions & 21 deletions

File tree

src/LitebaseClient.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ public function exec(array $input): ?QueryResult
161161
$parameters = [];
162162

163163
foreach ($input['parameters'] ?? [] as $param) {
164+
// Base64 encode BLOB values for HTTP transport (JSON serialization)
165+
// The binary streaming transport handles raw binary data
166+
if ($param['type'] === 'BLOB' && $this->transport instanceof HttpTransport) {
167+
$param['value'] = base64_encode((string) $param['value']);
168+
}
169+
164170
$parameters[] = new StatementParameter($param);
165171
}
166172

@@ -235,7 +241,7 @@ public function withTransport(string $transportType): LitebaseClient
235241
$this->transport = new HttpStreamingTransport($this->configuration);
236242
break;
237243
default:
238-
throw new Exception('Invalid transport type: '.$transportType);
244+
throw new Exception('Invalid transport type: ' . $transportType);
239245
}
240246

241247
return $this;

src/LitebaseStatement.php

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -60,29 +60,29 @@ public function bindParam(
6060
*/
6161
public function bindValue(int|string $parameter, mixed $value, int $data_type = PDO::PARAM_STR): bool
6262
{
63-
$type = 'NULL';
63+
$type = ColumnType::TEXT->name;
6464

6565
switch ($data_type) {
6666
case PDO::PARAM_BOOL:
6767
case PDO::PARAM_INT:
68-
$type = 'INTEGER';
68+
$type = ColumnType::INTEGER->name;
6969
break;
7070
case PDO::PARAM_STR:
71-
$type = 'TEXT';
71+
// Auto-detect float type when PDO::PARAM_STR is passed
72+
if (is_float($value)) {
73+
$type = ColumnType::FLOAT->name;
74+
} else {
75+
$type = ColumnType::TEXT->name;
76+
}
7277
break;
7378
case PDO::PARAM_NULL:
74-
$type = 'NULL';
79+
$type = ColumnType::NULL->name;
7580
break;
76-
// TODO: Test BLOB type
7781
case PDO::PARAM_LOB:
78-
$type = 'BLOB';
82+
$type = ColumnType::BLOB->name;
7983
break;
80-
// TODO: Add a case for float type
81-
// case PDO::PARAM_FLOAT:
82-
// $type = "REAL";
83-
// break;
8484
default:
85-
$type = 'TEXT'; // Default to TEXT if no match
85+
$type = ColumnType::TEXT->name; // Default to TEXT if no match
8686
break;
8787
}
8888

@@ -164,11 +164,11 @@ public function execute(?array $params = null): bool
164164
foreach ($params as $key => $value) {
165165
// Determine the type based on the value
166166
$type = match (true) {
167-
$value === null => 'NULL',
168-
is_int($value) => 'INTEGER',
169-
is_float($value) => 'REAL',
170-
is_bool($value) => 'INTEGER',
171-
default => 'TEXT',
167+
$value === null => ColumnType::NULL->name,
168+
is_int($value) => ColumnType::INTEGER->name,
169+
is_float($value) => ColumnType::FLOAT->name,
170+
is_bool($value) => ColumnType::INTEGER->name,
171+
default => ColumnType::TEXT->name,
172172
};
173173

174174
$transformedParams[$key] = [
@@ -212,14 +212,14 @@ public function execute(?array $params = null): bool
212212
$columns = $this->columns ?? [];
213213

214214
return array_combine(
215-
array_map(fn ($col) => $col['name'], $columns),
215+
array_map(fn($col) => $col['name'], $columns),
216216
$row
217217
);
218218
}, $this->result->rows);
219219
}
220220

221-
if (isset($this->result->rowCount)) {
222-
$this->rowCount = $this->result->rowCount;
221+
if (isset($this->result->changes)) {
222+
$this->rowCount = $this->result->changes;
223223
}
224224

225225
return true;
@@ -282,6 +282,9 @@ public function fetchColumn($columnIndex = 0): mixed
282282
return $value !== false ? $row[$value] : null;
283283
}
284284

285+
/**
286+
* {@inheritDoc}
287+
*/
285288
public function rowCount(): int
286289
{
287290
return $this->rowCount;

tests/Integration/LitebasePDOTest.php

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
'name' => 'test',
3030
]));
3131
} catch (\Exception $e) {
32-
throw new \RuntimeException('Failed to connect to Litebase server for integration tests: '.$e->getMessage());
32+
throw new \RuntimeException('Failed to connect to Litebase server for integration tests: ' . $e->getMessage());
3333
}
3434
});
3535

@@ -140,4 +140,92 @@
140140
expect($user['name'])->toBe('Alice');
141141
expect($user['email'])->toBe('alice@example.com');
142142
});
143+
144+
test('can handle all column data types', function () {
145+
$client = new LitebaseClient(
146+
Configuration::create([
147+
'host' => 'localhost',
148+
'port' => '8888',
149+
'username' => 'root',
150+
'password' => 'password',
151+
'database' => 'test/main',
152+
])
153+
);
154+
155+
$pdo = new LitebasePDO($client);
156+
157+
// Create table with all supported column types
158+
$pdo->exec('CREATE TABLE IF NOT EXISTS type_test (
159+
id INTEGER PRIMARY KEY AUTOINCREMENT,
160+
int_col INTEGER,
161+
float_col REAL,
162+
text_col TEXT,
163+
blob_col BLOB,
164+
null_col TEXT
165+
)');
166+
167+
// Insert data with different types using execute with params
168+
$statement = $pdo->prepare('INSERT INTO type_test (int_col, float_col, text_col, blob_col, null_col) VALUES (?, ?, ?, ?, ?)');
169+
170+
$blobData = hex2bin('48656c6c6f20576f726c64'); // "Hello World" as binary
171+
172+
$statement->execute([
173+
42, // INTEGER
174+
3.14159, // FLOAT
175+
'Hello World', // TEXT
176+
$blobData, // BLOB
177+
null, // NULL
178+
]);
179+
180+
expect($statement->rowCount())->toBe(1);
181+
182+
// Now test bindValue for a second insert
183+
$statement2 = $pdo->prepare('INSERT INTO type_test (int_col, float_col, text_col, blob_col, null_col) VALUES (?, ?, ?, ?, ?)');
184+
185+
$blobData2 = hex2bin('776f726c6420686921'); // "world hi!" as binary
186+
187+
$statement2->bindValue(1, 99, PDO::PARAM_INT);
188+
$statement2->bindValue(2, 2.71828, PDO::PARAM_STR);
189+
$statement2->bindValue(3, 'Test String', PDO::PARAM_STR);
190+
$statement2->bindValue(4, $blobData2, PDO::PARAM_LOB);
191+
$statement2->bindValue(5, null, PDO::PARAM_NULL);
192+
193+
$statement2->execute();
194+
195+
expect($statement2->rowCount())->toBe(1);
196+
197+
// Retrieve and verify the first row
198+
$statement = $pdo->prepare('SELECT * FROM type_test WHERE int_col = ?');
199+
$statement->execute([42]);
200+
201+
/** @var array<string, mixed> $row */
202+
$row = $statement->fetch(PDO::FETCH_ASSOC);
203+
/** @var float $floatValue */
204+
$floatValue = $row['float_col'];
205+
/** @var string $blobValue */
206+
$blobValue = $row['blob_col'];
207+
208+
expect($row)->not->toBeNull();
209+
expect($row['int_col'])->toBe(42);
210+
expect($row['float_col'])->toBeFloat();
211+
expect(abs($floatValue - 3.14159))->toBeLessThan(0.00001);
212+
expect($row['text_col'])->toBe('Hello World');
213+
expect($row['blob_col'])->toBe($blobData);
214+
expect(bin2hex($blobValue))->toBe('48656c6c6f20576f726c64');
215+
expect($row['null_col'])->toBeNull();
216+
217+
// Retrieve and verify the second row
218+
$statement = $pdo->prepare('SELECT * FROM type_test WHERE int_col = ?');
219+
$statement->execute([99]);
220+
221+
/** @var array<string, mixed> $row2 */
222+
$row2 = $statement->fetch(PDO::FETCH_ASSOC);
223+
224+
expect($row2)->not->toBeNull();
225+
expect($row2['int_col'])->toBe(99);
226+
expect($row2['float_col'])->toBeFloat();
227+
expect($row2['text_col'])->toBe('Test String');
228+
expect($row2['blob_col'])->toBe($blobData2);
229+
expect($row2['null_col'])->toBeNull();
230+
});
143231
});

0 commit comments

Comments
 (0)