Skip to content

Commit 3c37290

Browse files
committed
Add support to pass driver flags to DBA handlers
Currently only LMDB with DBA_LMDB_USE_SUB_DIR/DBA_LMDB_NO_SUB_DIR are supported
1 parent 79d831f commit 3c37290

10 files changed

+162
-9
lines changed

NEWS

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ PHP NEWS
1515

1616
- DBA:
1717
. Fixed LMDB driver memory leak on DB creation failure (Girgias)
18+
. Fixed GH-8856 (dba: lmdb: allow to override the MDB_NOSUBDIR flag). (Girgias)
1819

1920
- Random:
2021
. Fixed bug GH-9067 (random extension is not thread safe). (cmb)

UPGRADING

+6-1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ PHP 8.2 UPGRADE NOTES
8888
. Exposed multiple new constants from libcurl 7.62 to 7.80.
8989
. Added new function curl_upkeep() to perform any connection upkeep checks.
9090

91+
- DBA:
92+
. The LMDB Driver now accepts the DBA_LMDB_USE_SUB_DIR or DBA_LMDB_NO_SUB_DIR
93+
flags to determine if it should create a sub directory or not when creating
94+
a database file.
95+
9196
- OCI8:
9297
. Added an oci8.prefetch_lob_size directive and oci_set_prefetch_lob()
9398
function to tune LOB query performance by reducing the number of
@@ -183,7 +188,7 @@ PHP 8.2 UPGRADE NOTES
183188

184189
- DBA
185190
. dba_open() and dba_popen() now have the following enforced function signature
186-
dba_open(string $path, string $mode, ?string $handler = null, int $permission = 0o644, int $map_size = 0)
191+
dba_open(string $path, string $mode, ?string $handler = null, int $permission = 0o644, int $map_size = 0, ?int $flags = null)
187192
. dba_fetch()'s optional skip argument is now at the end in line with
188193
PHP userland semantics its signature now is:
189194
dba_fetch(string|array $key, $dba, int $skip = 0): string|false

ext/dba/dba.c

+19-4
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ PHP_MINIT_FUNCTION(dba)
359359
REGISTER_INI_ENTRIES();
360360
le_db = zend_register_list_destructors_ex(dba_close_rsrc, NULL, "dba", module_number);
361361
le_pdb = zend_register_list_destructors_ex(dba_close_pe_rsrc, dba_close_rsrc, "dba persistent", module_number);
362+
register_dba_symbols(module_number);
362363
return SUCCESS;
363364
}
364365
/* }}} */
@@ -478,10 +479,12 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent)
478479
zend_string *handler_str = NULL;
479480
zend_long permission = 0644;
480481
zend_long map_size = 0;
482+
zend_long driver_flags = DBA_DEFAULT_DRIVER_FLAGS;
483+
bool is_flags_null = true;
481484
zend_string *persistent_resource_key = NULL;
482485

483-
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "PS|S!ll", &path, &mode, &handler_str,
484-
&permission, &map_size)) {
486+
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "PS|S!lll!", &path, &mode, &handler_str,
487+
&permission, &map_size, &driver_flags, &is_flags_null)) {
485488
RETURN_THROWS();
486489
}
487490

@@ -503,6 +506,11 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent)
503506
RETURN_THROWS();
504507
}
505508

509+
if (!is_flags_null && driver_flags < 0) {
510+
zend_argument_value_error(6, "must be greater or equal than 0");
511+
RETURN_THROWS();
512+
}
513+
506514
if (persistent) {
507515
zend_resource *le;
508516

@@ -720,6 +728,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent)
720728
info->mode = modenr;
721729
info->file_permission = permission;
722730
info->map_size = map_size;
731+
info->driver_flags = driver_flags;
723732
info->flags = (hptr->flags & ~DBA_LOCK_ALL) | (lock_flag & DBA_LOCK_ALL) | (persistent ? DBA_PERSISTENT : 0);
724733
info->lock.mode = lock_mode;
725734

@@ -835,9 +844,15 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent)
835844
}
836845
}
837846

838-
if (error || hptr->open(info, &error) != SUCCESS) {
847+
if (error || hptr->open(info, &error) == FAILURE) {
839848
dba_close(info);
840-
php_error_docref(NULL, E_WARNING, "Driver initialization failed for handler: %s%s%s", hptr->name, error?": ":"", error?error:"");
849+
if (EXPECTED(!EG(exception))) {
850+
if (error) {
851+
php_error_docref(NULL, E_WARNING, "Driver initialization failed for handler: %s: %s", hptr->name, error);
852+
} else {
853+
php_error_docref(NULL, E_WARNING, "Driver initialization failed for handler: %s", hptr->name);
854+
}
855+
}
841856
FREE_PERSISTENT_RESOURCE_KEY();
842857
RETURN_FALSE;
843858
}

ext/dba/dba.stub.php

+12-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,21 @@
22

33
/** @generate-class-entries */
44

5+
#ifdef DBA_LMDB
6+
/** @var int */
7+
const DBA_LMDB_USE_SUB_DIR = 0;
8+
/**
9+
* @var int
10+
* @cvalue MDB_NOSUBDIR
11+
*/
12+
const DBA_LMDB_NO_SUB_DIR = UNKNOWN;
13+
#endif
14+
515
/** @return resource|false */
6-
function dba_popen(string $path, string $mode, ?string $handler = null, int $permission = 0o644, int $map_size = 0) {}
16+
function dba_popen(string $path, string $mode, ?string $handler = null, int $permission = 0o644, int $map_size = 0, ?int $flags = null) {}
717

818
/** @return resource|false */
9-
function dba_open(string $path, string $mode, ?string $handler = null, int $permission = 0o644, int $map_size = 0) {}
19+
function dba_open(string $path, string $mode, ?string $handler = null, int $permission = 0o644, int $map_size = 0, ?int $flags = null) {}
1020

1121
/** @param resource $dba */
1222
function dba_close($dba): void {}

ext/dba/dba_arginfo.h

+12-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/dba/dba_lmdb.c

+17-1
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,28 @@ DBA_OPEN_FUNC(lmdb)
4040
{
4141
MDB_env *env;
4242
MDB_txn *txn;
43-
int rc, flags = MDB_NOSUBDIR;
43+
int rc;
4444
int mode = info->file_permission;
4545
zend_long map_size = info->map_size;
4646

4747
ZEND_ASSERT(map_size >= 0);
4848

49+
/* By default use the MDB_NOSUBDIR flag */
50+
int flags = MDB_NOSUBDIR;
51+
/* Use flags passed by the user for driver flags */
52+
if (info->driver_flags != DBA_DEFAULT_DRIVER_FLAGS) {
53+
ZEND_ASSERT(info->driver_flags >= 0);
54+
switch (info->driver_flags) {
55+
case 0:
56+
case MDB_NOSUBDIR:
57+
flags = info->driver_flags;
58+
break;
59+
default:
60+
zend_argument_value_error(6, "must be either DBA_LMDB_USE_SUB_DIR or DBA_LMDB_NO_SUB_DIR for LMDB driver");
61+
return FAILURE;
62+
}
63+
}
64+
4965
/* Add readonly flag if DB is opened in read only mode */
5066
if (info->mode == DBA_READER) {
5167
flags |= MDB_RDONLY;

ext/dba/php_dba.h

+4
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,16 @@ typedef struct dba_info {
4444
int fd;
4545
int file_permission;
4646
zend_long map_size;
47+
/* -1 for default driver flags */
48+
zend_long driver_flags;
4749
/* private */
4850
int flags; /* whether and how dba did locking and other flags*/
4951
struct dba_handler *hnd;
5052
dba_lock lock;
5153
} dba_info;
5254

55+
#define DBA_DEFAULT_DRIVER_FLAGS -1
56+
5357
#define DBA_LOCK_READER (0x0001)
5458
#define DBA_LOCK_WRITER (0x0002)
5559
#define DBA_LOCK_CREAT (0x0004)

ext/dba/php_lmdb.h

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#ifdef DBA_LMDB
55

66
#include "php_dba.h"
7+
#include <lmdb.h>
78

89
DBA_FUNCS(lmdb);
910

ext/dba/tests/dba_flags_arg.phpt

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
DBA new flags ValueError test
3+
--EXTENSIONS--
4+
dba
5+
--FILE--
6+
<?php
7+
try {
8+
dba_open('irrelevant', 'c', 'handler', flags: -1);
9+
} catch (\ValueError $e) {
10+
echo $e->getMessage(), \PHP_EOL;
11+
}
12+
?>
13+
--EXPECT--
14+
dba_open(): Argument #6 ($flags) must be greater or equal than 0

ext/dba/tests/dba_lmdb_flags.phpt

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
--TEST--
2+
DBA LMDB handler flags test
3+
--EXTENSIONS--
4+
dba
5+
--SKIPIF--
6+
<?php
7+
$handler = 'lmdb';
8+
require_once __DIR__ .'/skipif.inc';
9+
?>
10+
--FILE--
11+
<?php
12+
$handler = 'lmdb';
13+
14+
// Pass bogus flag
15+
try {
16+
$db_file = dba_open('irrelevant', 'c', $handler, flags: 45);
17+
} catch (\ValueError $e) {
18+
echo $e->getMessage(), \PHP_EOL;
19+
}
20+
21+
// Use current test folder
22+
$db_filename = __DIR__;
23+
$db_file = dba_open($db_filename, 'c', $handler, flags: DBA_LMDB_USE_SUB_DIR);
24+
assert($db_file !== false);
25+
26+
// Check insertion of data
27+
dba_insert("key1", "Content String 1", $db_file);
28+
dba_insert("key2", "Content String 2", $db_file);
29+
dba_insert("key3", "Third Content String", $db_file);
30+
dba_insert("key4", "Another Content String", $db_file);
31+
dba_insert("key5", "The last content string", $db_file);
32+
33+
// Remove some data
34+
dba_delete("key3", $db_file);
35+
dba_delete("key1", $db_file);
36+
37+
// Fetch data
38+
$key = dba_firstkey($db_file);
39+
$total_keys = 0;
40+
while ($key) {
41+
echo $key, ': ', dba_fetch($key, $db_file), \PHP_EOL;
42+
$key = dba_nextkey($db_file);
43+
$total_keys++;
44+
}
45+
echo 'Total keys: ', $total_keys, \PHP_EOL;
46+
for ($i = 1; $i < 6; $i++) {
47+
echo "Key $i exists? ", dba_exists("key$i", $db_file) ? "Y" : "N", \PHP_EOL;
48+
}
49+
50+
// Replace second key data
51+
dba_replace("key2", "Content 2 replaced", $db_file);
52+
echo dba_fetch("key2", $db_file), \PHP_EOL;
53+
54+
// Close handler
55+
dba_close($db_file);
56+
57+
?>
58+
--CLEAN--
59+
<?php
60+
$db_filename = __DIR__ . '/data.mdb';
61+
$db_loc_filename = __DIR__ . '/lock.mdb';
62+
@unlink($db_filename);
63+
@unlink($db_loc_filename);
64+
?>
65+
--EXPECT--
66+
dba_open(): Argument #6 ($flags) must be either DBA_LMDB_USE_SUB_DIR or DBA_LMDB_NO_SUB_DIR for LMDB driver
67+
key2: Content String 2
68+
key4: Another Content String
69+
key5: The last content string
70+
Total keys: 3
71+
Key 1 exists? N
72+
Key 2 exists? Y
73+
Key 3 exists? N
74+
Key 4 exists? Y
75+
Key 5 exists? Y
76+
Content 2 replaced

0 commit comments

Comments
 (0)