summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-05-05 04:27:29 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:51:45 -0500
commit232bc1503fc0e3f85b4711f077d2566dc0f0c823 (patch)
tree14e4a2736ab44368bdb27296ddbe5fb3a05fd5fc /source4
parentaf66c31e44bcb052f35f9b1de8e997149fddac89 (diff)
downloadsamba-232bc1503fc0e3f85b4711f077d2566dc0f0c823.tar.gz
samba-232bc1503fc0e3f85b4711f077d2566dc0f0c823.tar.bz2
samba-232bc1503fc0e3f85b4711f077d2566dc0f0c823.zip
r490: - expanded the test suite to test modify and delete operations
- made yet another attempt to make ldb const clean. - "make test" now runs both the tdb and ldap backend tests, and run the ldbtest utility with and without indexing - added prototypes in ldb.h for ldb_msg_*() public functions (This used to be commit 01e87406768cb5a98ac8530a2f361a4987a36cd3)
Diffstat (limited to 'source4')
-rw-r--r--source4/lib/ldb/Makefile.ldb13
-rw-r--r--source4/lib/ldb/common/ldb.c2
-rw-r--r--source4/lib/ldb/common/ldb_ldif.c5
-rw-r--r--source4/lib/ldb/include/ldb.h45
-rw-r--r--source4/lib/ldb/ldb_ldap/ldb_ldap.c2
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_cache.c36
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_index.c22
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_search.c12
-rwxr-xr-xsource4/lib/ldb/tests/init_slapd.sh8
-rwxr-xr-xsource4/lib/ldb/tests/test-generic.sh15
-rwxr-xr-xsource4/lib/ldb/tests/test-tdb.sh1
-rw-r--r--source4/lib/ldb/tools/ldbsearch.c4
-rw-r--r--source4/lib/ldb/tools/ldbtest.c98
13 files changed, 222 insertions, 41 deletions
diff --git a/source4/lib/ldb/Makefile.ldb b/source4/lib/ldb/Makefile.ldb
index d05ad546a2..0b8fdfe28f 100644
--- a/source4/lib/ldb/Makefile.ldb
+++ b/source4/lib/ldb/Makefile.ldb
@@ -11,7 +11,7 @@ endif
TDBDIR=../tdb
-CFLAGS=-Wall -g -Iinclude -I. -I.. -DSTANDALONE=1 -DUSE_MMAP=1 $(LDAP_FLAGS)
+CFLAGS=-Wall -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -g -Iinclude -I. -I.. -DSTANDALONE=1 -DUSE_MMAP=1 $(LDAP_FLAGS)
LIB_FLAGS=-Llib -lldb $(LDAP_LIBS)
TDB_OBJ=$(TDBDIR)/tdb.o $(TDBDIR)/spinlock.o
@@ -28,7 +28,7 @@ OBJS = $(COMMON_OBJ) $(LDB_TDB_OBJ) $(TDB_OBJ) $(LDB_LDAP_OBJ)
LDB_LIB = lib/libldb.a
-BINS = bin/ldbadd bin/ldbsearch bin/ldbdel bin/ldbmodify bin/ldbedit
+BINS = bin/ldbadd bin/ldbsearch bin/ldbdel bin/ldbmodify bin/ldbedit bin/ldbtest
LIBS = $(LDB_LIB)($(OBJS))
@@ -71,5 +71,12 @@ proto:
etags:
etags */*.[ch]
-test:
+test-tdb:
+ @echo "STARTING TDB BACKEND TEST"
tests/test-tdb.sh
+
+test-ldap:
+ @echo "STARTING LDAP BACKEND TEST"
+ tests/test-ldap.sh
+
+test: test-tdb test-ldap
diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c
index ce21d1d9e2..86d0dd9e9b 100644
--- a/source4/lib/ldb/common/ldb.c
+++ b/source4/lib/ldb/common/ldb.c
@@ -81,7 +81,7 @@ int ldb_search(struct ldb_context *ldb,
const char *base,
enum ldb_scope scope,
const char *expression,
- const char * const *attrs, struct ldb_message ***res)
+ char * const *attrs, struct ldb_message ***res)
{
return ldb->ops->search(ldb, base, scope, expression, attrs, res);
}
diff --git a/source4/lib/ldb/common/ldb_ldif.c b/source4/lib/ldb/common/ldb_ldif.c
index 1ca585ca80..ef782e90e3 100644
--- a/source4/lib/ldb/common/ldb_ldif.c
+++ b/source4/lib/ldb/common/ldb_ldif.c
@@ -343,7 +343,7 @@ static char *next_chunk(int (*fgetc_fn)(void *), void *private_data)
/* simple ldif attribute parser */
-static int next_attr(char **s, char **attr, struct ldb_val *value)
+static int next_attr(char **s, const char **attr, struct ldb_val *value)
{
char *p;
int base64_encoded = 0;
@@ -454,7 +454,8 @@ struct ldb_ldif *ldif_read(int (*fgetc_fn)(void *), void *private_data)
{
struct ldb_ldif *ldif;
struct ldb_message *msg;
- char *attr=NULL, *chunk=NULL, *s;
+ const char *attr=NULL;
+ char *chunk=NULL, *s;
struct ldb_val value;
unsigned flags = 0;
diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h
index c0521ecffa..cee72c3c21 100644
--- a/source4/lib/ldb/include/ldb.h
+++ b/source4/lib/ldb/include/ldb.h
@@ -124,7 +124,7 @@ typedef int (*ldb_traverse_fn)(struct ldb_context *, const struct ldb_message *)
struct ldb_backend_ops {
int (*close)(struct ldb_context *);
int (*search)(struct ldb_context *, const char *, enum ldb_scope,
- const char *, const char * const [], struct ldb_message ***);
+ const char *, char * const [], struct ldb_message ***);
int (*search_free)(struct ldb_context *, struct ldb_message **);
int (*add_record)(struct ldb_context *, const struct ldb_message *);
int (*modify_record)(struct ldb_context *, const struct ldb_message *);
@@ -174,7 +174,7 @@ int ldb_search(struct ldb_context *ldb,
const char *base,
enum ldb_scope scope,
const char *expression,
- const char * const *attrs, struct ldb_message ***res);
+ char * const *attrs, struct ldb_message ***res);
/*
free a set of messages returned by ldb_search
@@ -223,3 +223,44 @@ struct ldb_ldif *ldif_read_file(FILE *f);
struct ldb_ldif *ldif_read_string(const char *s);
int ldif_write_file(FILE *f, const struct ldb_ldif *msg);
+
+/* useful functions for ldb_message structure manipulation */
+
+/* find an element within an message */
+struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
+ const char *attr_name);
+
+/* compare two ldb_val values - return 0 on match */
+int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2);
+
+/* find a value within an ldb_message_element */
+struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
+ struct ldb_val *val);
+
+/* add a new empty element to a ldb_message */
+int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags);
+
+/* add a element to a ldb_message */
+int ldb_msg_add(struct ldb_message *msg,
+ const struct ldb_message_element *el,
+ int flags);
+
+/* compare two message elements - return 0 on match */
+int ldb_msg_element_compare(struct ldb_message_element *el1,
+ struct ldb_message_element *el2);
+
+/* find elements in a message and convert to a specific type, with
+ a give default value if not found. Assumes that elements are
+ single valued */
+int ldb_msg_find_int(const struct ldb_message *msg,
+ const char *attr_name,
+ int default_value);
+unsigned int ldb_msg_find_uint(const struct ldb_message *msg,
+ const char *attr_name,
+ int default_value);
+double ldb_msg_find_double(const struct ldb_message *msg,
+ const char *attr_name,
+ double default_value);
+const char *ldb_msg_find_string(const struct ldb_message *msg,
+ const char *attr_name,
+ const char *default_value);
diff --git a/source4/lib/ldb/ldb_ldap/ldb_ldap.c b/source4/lib/ldb/ldb_ldap/ldb_ldap.c
index 26c29122ad..8723beeadc 100644
--- a/source4/lib/ldb/ldb_ldap/ldb_ldap.c
+++ b/source4/lib/ldb/ldb_ldap/ldb_ldap.c
@@ -207,7 +207,7 @@ static int lldb_add_msg_attr(struct ldb_message *msg,
*/
static int lldb_search(struct ldb_context *ldb, const char *base,
enum ldb_scope scope, const char *expression,
- const char * const *attrs, struct ldb_message ***res)
+ char * const *attrs, struct ldb_message ***res)
{
struct lldb_private *lldb = ldb->private_data;
int count, msg_count;
diff --git a/source4/lib/ldb/ldb_tdb/ldb_cache.c b/source4/lib/ldb/ldb_tdb/ldb_cache.c
index 5d61fd35b3..3c6ce63c2b 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_cache.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_cache.c
@@ -44,20 +44,42 @@ static int ltdb_baseinfo_init(struct ldb_context *ldb)
struct ldb_message msg;
struct ldb_message_element el;
struct ldb_val val;
+ int ret;
ltdb->sequence_number = 0;
msg.num_elements = 1;
msg.elements = &el;
- msg.dn = LTDB_BASEINFO;
- el.name = LTDB_SEQUENCE_NUMBER;
+ msg.dn = strdup(LTDB_BASEINFO);
+ if (!msg.dn) {
+ errno = ENOMEM;
+ return -1;
+ }
+ el.name = strdup(LTDB_SEQUENCE_NUMBER);
+ if (!el.name) {
+ free(msg.dn);
+ errno = ENOMEM;
+ return -1;
+ }
el.values = &val;
el.num_values = 1;
el.flags = 0;
- val.data = "0";
+ val.data = strdup("0");
+ if (!val.data) {
+ free(el.name);
+ free(msg.dn);
+ errno = ENOMEM;
+ return -1;
+ }
val.length = 1;
- return ltdb_store(ldb, &msg, TDB_INSERT);
+ ret = ltdb_store(ldb, &msg, TDB_INSERT);
+
+ free(msg.dn);
+ free(el.name);
+ free(val.data);
+
+ return ret;
}
/*
@@ -150,8 +172,8 @@ int ltdb_increase_sequence_number(struct ldb_context *ldb)
msg.num_elements = 1;
msg.elements = &el;
- msg.dn = LTDB_BASEINFO;
- el.name = LTDB_SEQUENCE_NUMBER;
+ msg.dn = strdup(LTDB_BASEINFO);
+ el.name = strdup(LTDB_SEQUENCE_NUMBER);
el.values = &val;
el.num_values = 1;
el.flags = LDB_FLAG_MOD_REPLACE;
@@ -161,6 +183,8 @@ int ltdb_increase_sequence_number(struct ldb_context *ldb)
ret = ltdb_modify_internal(ldb, &msg);
free(s);
+ free(msg.dn);
+ free(el.name);
if (ret == 0) {
ltdb->sequence_number += 1;
diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c
index d250bc10be..0b9581e52f 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_index.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_index.c
@@ -202,7 +202,10 @@ static int ltdb_index_dn_objectclass(struct ldb_context *ldb,
struct ldb_parse_tree tree2;
struct dn_list list2;
tree2.operation = LDB_OP_SIMPLE;
- tree2.u.simple.attr = LTDB_OBJECTCLASS;
+ tree2.u.simple.attr = strdup(LTDB_OBJECTCLASS);
+ if (!tree2.u.simple.attr) {
+ return -1;
+ }
tree2.u.simple.value = el->values[j];
if (ltdb_index_dn_objectclass(ldb, &tree2,
index_list, &list2) == 1) {
@@ -214,6 +217,7 @@ static int ltdb_index_dn_objectclass(struct ldb_context *ldb,
dn_list_free(&list2);
}
}
+ free(tree2.u.simple.attr);
}
}
}
@@ -488,7 +492,7 @@ static int ldb_index_filter(struct ldb_context *ldb, struct ldb_parse_tree *tree
const char *base,
enum ldb_scope scope,
const struct dn_list *dn_list,
- const char * const attrs[], struct ldb_message ***res)
+ char * const attrs[], struct ldb_message ***res)
{
int i;
unsigned int count = 0;
@@ -528,7 +532,7 @@ int ltdb_search_indexed(struct ldb_context *ldb,
const char *base,
enum ldb_scope scope,
struct ldb_parse_tree *tree,
- const char * const attrs[], struct ldb_message ***res)
+ char * const attrs[], struct ldb_message ***res)
{
struct ltdb_private *ltdb = ldb->private_data;
struct dn_list dn_list;
@@ -569,7 +573,10 @@ static int ltdb_index_add1_new(struct ldb_context *ldb,
}
msg->elements = el2;
- msg->elements[msg->num_elements].name = LTDB_IDX;
+ msg->elements[msg->num_elements].name = strdup(LTDB_IDX);
+ if (!msg->elements[msg->num_elements].name) {
+ return -1;
+ }
msg->elements[msg->num_elements].num_values = 0;
msg->elements[msg->num_elements].values = malloc_p(struct ldb_val);
if (!msg->elements[msg->num_elements].values) {
@@ -627,7 +634,7 @@ static int ltdb_index_add1(struct ldb_context *ldb, char *dn,
{
struct ldb_message msg;
char *dn_key;
- int ret, i;
+ int ret, i, added=0;
dn_key = ldb_dn_key(el->name, &el->values[v_idx]);
if (!dn_key) {
@@ -661,6 +668,7 @@ static int ltdb_index_add1(struct ldb_context *ldb, char *dn,
}
if (i == msg.num_elements) {
+ added = 1;
ret = ltdb_index_add1_new(ldb, &msg, el, dn);
} else {
ret = ltdb_index_add1_add(ldb, &msg, el, i, dn);
@@ -670,6 +678,10 @@ static int ltdb_index_add1(struct ldb_context *ldb, char *dn,
ret = ltdb_store(ldb, &msg, TDB_REPLACE);
}
+ if (added) {
+ free(msg.elements[i].name);
+ }
+
ltdb_search_dn1_free(ldb, &msg);
return ret;
diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c
index cce865e052..1dce8f83a2 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_search.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_search.c
@@ -148,7 +148,7 @@ static int msg_add_all_elements(struct ldb_message *ret,
*/
static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb,
const struct ldb_message *msg,
- const char * const *attrs)
+ char * const *attrs)
{
struct ldb_message *ret;
int i;
@@ -294,7 +294,7 @@ int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message
search the database for a single simple dn
*/
int ltdb_search_dn(struct ldb_context *ldb, char *dn,
- const char * const attrs[], struct ldb_message ***res)
+ char * const attrs[], struct ldb_message ***res)
{
int ret;
struct ldb_message msg, *msg2;
@@ -330,7 +330,7 @@ int ltdb_search_dn(struct ldb_context *ldb, char *dn,
return 0 on success, -1 on failure
*/
int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg,
- const char * const attrs[],
+ char * const attrs[],
unsigned int *count,
struct ldb_message ***res)
{
@@ -368,7 +368,7 @@ struct ltdb_search_info {
struct ldb_parse_tree *tree;
const char *base;
enum ldb_scope scope;
- const char * const *attrs;
+ char * const *attrs;
struct ldb_message **msgs;
int failures;
int count;
@@ -445,7 +445,7 @@ static int ltdb_search_full(struct ldb_context *ldb,
const char *base,
enum ldb_scope scope,
struct ldb_parse_tree *tree,
- const char * const attrs[], struct ldb_message ***res)
+ char * const attrs[], struct ldb_message ***res)
{
struct ltdb_private *ltdb = ldb->private_data;
int ret;
@@ -478,7 +478,7 @@ static int ltdb_search_full(struct ldb_context *ldb,
*/
int ltdb_search(struct ldb_context *ldb, const char *base,
enum ldb_scope scope, const char *expression,
- const char * const attrs[], struct ldb_message ***res)
+ char * const attrs[], struct ldb_message ***res)
{
struct ldb_parse_tree *tree;
int ret;
diff --git a/source4/lib/ldb/tests/init_slapd.sh b/source4/lib/ldb/tests/init_slapd.sh
index 67eecb031c..65700f6c18 100755
--- a/source4/lib/ldb/tests/init_slapd.sh
+++ b/source4/lib/ldb/tests/init_slapd.sh
@@ -5,7 +5,11 @@ export PATH=/usr/sbin:$PATH
rm -rf tests/tmp/db
mkdir -p tests/tmp/db
-killall slapd
+if pidof slapd > /dev/null; then
+ killall slapd
+fi
sleep 2
-killall -9 slapd
+if pidof slapd > /dev/null; then
+ killall -9 slapd
+fi
slapadd -f tests/slapd.conf < tests/init.ldif || exit 1
diff --git a/source4/lib/ldb/tests/test-generic.sh b/source4/lib/ldb/tests/test-generic.sh
index 79db49bb48..794b451074 100755
--- a/source4/lib/ldb/tests/test-generic.sh
+++ b/source4/lib/ldb/tests/test-generic.sh
@@ -1,8 +1,17 @@
echo "Adding base elements"
-bin/ldbadd tests/test.ldif
+bin/ldbadd tests/test.ldif || exit 1
echo "Modifying elements"
-bin/ldbmodify tests/test-modify.ldif
+bin/ldbmodify tests/test-modify.ldif || exit 1
echo "Showing modified record"
-bin/ldbsearch '(uid=uham)'
+bin/ldbsearch '(uid=uham)' || exit 1
+
+echo "Starting ldbtest"
+time bin/ldbtest -r 1000 -s 100 || exit 1
+
+echo "Adding index"
+bin/ldbadd tests/test-index.ldif || exit 1
+
+echo "Starting ldbtest indexed"
+time bin/ldbtest -r 1000 -s 5000 || exit 1
diff --git a/source4/lib/ldb/tests/test-tdb.sh b/source4/lib/ldb/tests/test-tdb.sh
index 1e21accac5..316828c31c 100755
--- a/source4/lib/ldb/tests/test-tdb.sh
+++ b/source4/lib/ldb/tests/test-tdb.sh
@@ -6,3 +6,4 @@ export LDB_URL="tdb://test.ldb"
rm -f test.ldb
. tests/test-generic.sh
+
diff --git a/source4/lib/ldb/tools/ldbsearch.c b/source4/lib/ldb/tools/ldbsearch.c
index e8275e87c1..541024dd2d 100644
--- a/source4/lib/ldb/tools/ldbsearch.c
+++ b/source4/lib/ldb/tools/ldbsearch.c
@@ -49,7 +49,7 @@ static void do_search(struct ldb_context *ldb,
const char *basedn,
int scope,
const char *expression,
- const char * const *attrs)
+ char * const *attrs)
{
int ret, i;
struct ldb_message **msgs;
@@ -84,7 +84,7 @@ static void do_search(struct ldb_context *ldb,
int main(int argc, char * const argv[])
{
struct ldb_context *ldb;
- const char * const * attrs = NULL;
+ char * const * attrs = NULL;
const char *ldb_url;
const char *basedn = NULL;
int opt;
diff --git a/source4/lib/ldb/tools/ldbtest.c b/source4/lib/ldb/tools/ldbtest.c
index b7d1d22db8..bcb8bdcb16 100644
--- a/source4/lib/ldb/tools/ldbtest.c
+++ b/source4/lib/ldb/tools/ldbtest.c
@@ -36,12 +36,12 @@
static struct timeval tp1,tp2;
-static void start_timer()
+static void start_timer(void)
{
gettimeofday(&tp1,NULL);
}
-static double end_timer()
+static double end_timer(void)
{
gettimeofday(&tp2,NULL);
return((tp2.tv_sec - tp1.tv_sec) +
@@ -108,6 +108,8 @@ static void add_records(struct ldb_context *ldb,
vals[5][0].data = name;
vals[5][0].length = strlen(vals[5][0].data);
+ ldb_delete(ldb, msg.dn);
+
if (ldb_add(ldb, &msg) != 0) {
printf("Add of %s failed - %s\n", name, ldb_errstring(ldb));
exit(1);
@@ -126,6 +128,83 @@ static void add_records(struct ldb_context *ldb,
printf("\n");
}
+static void modify_records(struct ldb_context *ldb,
+ const char *basedn,
+ int count)
+{
+ struct ldb_message msg;
+ int i;
+
+ for (i=0;i<count;i++) {
+ struct ldb_message_element el[3];
+ struct ldb_val vals[3];
+ char *name;
+
+ asprintf(&name, "Test%d", i);
+ asprintf(&msg.dn, "cn=%s,%s", name, basedn);
+
+ msg.num_elements = 3;
+ msg.elements = el;
+
+ el[0].flags = LDB_FLAG_MOD_DELETE;
+ el[0].name = "mail";
+ el[0].num_values = 0;
+
+ el[1].flags = LDB_FLAG_MOD_ADD;
+ el[1].name = "mail";
+ el[1].num_values = 1;
+ el[1].values = &vals[1];
+ asprintf((char **)&vals[1].data, "%s@other.example.com", name);
+ vals[1].length = strlen(vals[1].data);
+
+ el[2].flags = LDB_FLAG_MOD_REPLACE;
+ el[2].name = "mail";
+ el[2].num_values = 1;
+ el[2].values = &vals[2];
+ asprintf((char **)&vals[2].data, "%s@other2.example.com", name);
+ vals[2].length = strlen(vals[2].data);
+
+ if (ldb_modify(ldb, &msg) != 0) {
+ printf("Modify of %s failed - %s\n", name, ldb_errstring(ldb));
+ exit(1);
+ }
+
+ printf("Modifying uid %s\r", name);
+ fflush(stdout);
+
+ free(name);
+ free(msg.dn);
+ free(vals[1].data);
+ free(vals[2].data);
+ }
+
+ printf("\n");
+}
+
+
+static void delete_records(struct ldb_context *ldb,
+ const char *basedn,
+ int count)
+{
+ int i;
+
+ for (i=0;i<count;i++) {
+ char *dn;
+ asprintf(&dn, "cn=Test%d,%s", i, basedn);
+
+ printf("Deleting uid Test%d\r", i);
+ fflush(stdout);
+
+ if (ldb_delete(ldb, dn) != 0) {
+ printf("Delete of %s failed - %s\n", dn, ldb_errstring(ldb));
+ exit(1);
+ }
+ free(dn);
+ }
+
+ printf("\n");
+}
+
static void search_uid(struct ldb_context *ldb, int nrecords, int nsearches)
{
int i;
@@ -164,18 +243,21 @@ static void search_uid(struct ldb_context *ldb, int nrecords, int nsearches)
static void start_test(struct ldb_context *ldb, int nrecords, int nsearches)
{
- printf("Adding %d records\n", nrecords);
+ const char *base = "ou=Ldb Test,ou=People,o=University of Michigan,c=US";
- add_records(ldb, "ou=Ldb Test,ou=People,o=University of Michigan,c=US",
- nrecords);
+ printf("Adding %d records\n", nrecords);
+ add_records(ldb, base, nrecords);
printf("Starting search on uid\n");
-
start_timer();
-
search_uid(ldb, nrecords, nsearches);
-
printf("uid search took %.2f seconds\n", end_timer());
+
+ printf("Modifying records\n");
+ modify_records(ldb, base, nrecords);
+
+ printf("Deleting records\n");
+ delete_records(ldb, base, nrecords);
}