From 78d8d6e06d94f87b6f4fe4c9467517da217d8985 Mon Sep 17 00:00:00 2001
From: Pierangelo Masarati <ando@openldap.org>
Date: Thu, 22 Mar 2007 23:10:56 +0000
Subject: [PATCH] add support for pagedResults to back-sql (ITS#4888)

---
 servers/slapd/back-sql/init.c   |   1 +
 servers/slapd/back-sql/search.c | 235 +++++++++++++++++++++++++++++++-
 tests/data/sql-read.out         | 136 +++++++++---------
 tests/scripts/sql-test000-read  |  77 ++++++-----
 4 files changed, 342 insertions(+), 107 deletions(-)

diff --git a/servers/slapd/back-sql/init.c b/servers/slapd/back-sql/init.c
index df67a50006..59876d3d18 100644
--- a/servers/slapd/back-sql/init.c
+++ b/servers/slapd/back-sql/init.c
@@ -40,6 +40,7 @@ sql_back_initialize(
 #if 0 /* SLAP_CONTROL_X_TREE_DELETE */
 		SLAP_CONTROL_X_TREE_DELETE,
 #endif /* SLAP_CONTROL_X_TREE_DELETE */
+		LDAP_CONTROL_PAGEDRESULTS,
 		NULL
 	};
 
diff --git a/servers/slapd/back-sql/search.c b/servers/slapd/back-sql/search.c
index 0e57413933..5cb2c38a53 100644
--- a/servers/slapd/back-sql/search.c
+++ b/servers/slapd/back-sql/search.c
@@ -42,6 +42,23 @@ static int backsql_process_filter_like( backsql_srch_info *bsi,
 static int backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, 
 		backsql_at_map_rec *at );
 
+/* For LDAP_CONTROL_PAGEDRESULTS, a 32 bit cookie is available to keep track of
+   the state of paged results. The ldap_entries.id and oc_map_id values of the
+   last entry returned are used as the cookie, so 6 bits are used for the OC id
+   and the other 26 for ldap_entries ID number. If your max(oc_map_id) is more
+   than 63, you will need to steal more bits from ldap_entries ID number and
+   put them into the OC ID part of the cookie. */
+#define SQL_TO_PAGECOOKIE(id, oc) (((id) << 6 ) | ((oc) & 0x3F))
+#define PAGECOOKIE_TO_SQL_ID(pc) ((pc) >> 6)
+#define PAGECOOKIE_TO_SQL_OC(pc) ((pc) & 0x3F)
+
+static int parse_paged_cookie( Operation *op, SlapReply *rs );
+
+static void send_paged_response( 
+	Operation *op,
+	SlapReply *rs,
+	ID  *lastid );
+
 static int
 backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
 {
@@ -1517,6 +1534,28 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
 		assert( 0 );
 	}
 
+	/* If paged results are in effect, ignore low ldap_entries.id numbers */
+	if ( get_pagedresults(bsi->bsi_op) > SLAP_CONTROL_IGNORED ) {
+		unsigned long lowid = 0;
+
+		/* Pick up the previous ldap_entries.id if the previous page ended in this objectClass */
+		if ( bsi->bsi_oc->bom_id == PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ) )
+		{
+			lowid = PAGECOOKIE_TO_SQL_ID( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie );
+		}
+		if ( lowid ) {
+			char lowidstring[48];
+			int  lowidlen;
+
+			lowidlen = snprintf( lowidstring, 48, " AND ldap_entries.id>%d", lowid );
+			backsql_strfcat_x( &bsi->bsi_join_where,
+					bsi->bsi_op->o_tmpmemctx,
+					"l",
+					(ber_len_t)lowidlen,
+					lowidstring );
+		}
+	}
+
 	rc = backsql_process_filter( bsi, bsi->bsi_filter );
 	if ( rc > 0 ) {
 		struct berbuf	bb = BB_NULL;
@@ -1596,6 +1635,14 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
 		return BACKSQL_AVL_STOP;
 	}
 
+	/* If paged results have already completed this objectClass, skip it */
+	if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
+		if ( oc->bom_id < PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)op->o_pagedresults_state)->ps_cookie ) )
+		{
+			return BACKSQL_AVL_CONTINUE;
+		}
+	}
+
 	if ( bsi->bsi_n_candidates == -1 ) {
 		Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
 			"unchecked limit has been overcome\n", 0, 0, 0 );
@@ -1921,6 +1968,7 @@ backsql_search( Operation *op, SlapReply *rs )
 	backsql_srch_info	bsi = { 0 };
 	backsql_entryID		*eid = NULL;
 	struct berval		nbase = BER_BVNULL;
+	unsigned long 		lastid = 0;
 
 	Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): "
 		"base=\"%s\", filter=\"%s\", scope=%d,", 
@@ -2057,6 +2105,16 @@ backsql_search( Operation *op, SlapReply *rs )
 		( op->ors_limit->lms_s_unchecked == -1 ? -2 :
 		( op->ors_limit->lms_s_unchecked ) ) );
 
+	/* If paged results are in effect, check the paging cookie */
+	if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
+		PagedResultsState *ps = op->o_pagedresults_state;
+		rs->sr_err = parse_paged_cookie( op, rs );
+		if ( rs->sr_err != LDAP_SUCCESS ) {
+			send_ldap_result( op, rs );
+			goto done;
+		}
+	}
+
 	switch ( bsi.bsi_scope ) {
 	case LDAP_SCOPE_BASE:
 	case BACKSQL_SCOPE_BASE_LIKE:
@@ -2084,9 +2142,9 @@ backsql_search( Operation *op, SlapReply *rs )
 		/*
 		 * for each objectclass we try to construct query which gets IDs
 		 * of entries matching LDAP query filter and scope (or at least 
-		 * candidates), and get the IDs
+		 * candidates), and get the IDs. Do this in ID order for paging.
 		 */
-		avl_apply( bi->sql_oc_by_oc, backsql_oc_get_candidates,
+		avl_apply( bi->sql_oc_by_id, backsql_oc_get_candidates,
 				&bsi, BACKSQL_AVL_STOP, AVL_INORDER );
 
 		/* check for abandon */
@@ -2329,6 +2387,16 @@ backsql_search( Operation *op, SlapReply *rs )
 
 		if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE )
 		{
+			/* If paged results are in effect, see if the page limit was exceeded */
+			if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
+				if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size )
+				{
+					e = NULL;
+					send_paged_response( op, rs, &lastid );
+					goto done;
+				}
+				lastid = SQL_TO_PAGECOOKIE( eid->eid_id, eid->eid_oc_id );
+			}
 			rs->sr_attrs = op->ors_attrs;
 			rs->sr_operational_attrs = NULL;
 			rs->sr_entry = e;
@@ -2374,7 +2442,11 @@ end_of_search:;
 
 send_results:;
 	if ( rs->sr_err != SLAPD_ABANDON ) {
-		send_ldap_result( op, rs );
+		if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
+			send_paged_response( op, rs, NULL );
+		} else {
+			send_ldap_result( op, rs );
+		}
 	}
 
 	/* cleanup in case of abandon */
@@ -2566,3 +2638,160 @@ backsql_entry_release(
 
 	return 0;
 }
+
+
+/* This function is copied verbatim from back-bdb/search.c */
+static int
+parse_paged_cookie( Operation *op, SlapReply *rs )
+{
+	LDAPControl	**c;
+	int		rc = LDAP_SUCCESS;
+	ber_tag_t	tag;
+	ber_int_t	size;
+	BerElement	*ber;
+	struct berval	cookie = BER_BVNULL;
+	PagedResultsState *ps = op->o_pagedresults_state;
+
+	/* this function must be invoked only if the pagedResults
+	 * control has been detected, parsed and partially checked
+	 * by the frontend */
+	assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED );
+
+	/* look for the appropriate ctrl structure */
+	for ( c = op->o_ctrls; c[0] != NULL; c++ ) {
+		if ( strcmp( c[0]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 )
+		{
+			break;
+		}
+	}
+
+	if ( c[0] == NULL ) {
+		rs->sr_text = "missing pagedResults control";
+		return LDAP_PROTOCOL_ERROR;
+	}
+
+	/* Tested by frontend */
+	assert( c[0]->ldctl_value.bv_len > 0 );
+
+	/* Parse the control value
+	 *	realSearchControlValue ::= SEQUENCE {
+	 *		size	INTEGER (0..maxInt),
+	 *				-- requested page size from client
+	 *				-- result set size estimate from server
+	 *		cookie	OCTET STRING
+	 * }
+	 */
+	ber = ber_init( &c[0]->ldctl_value );
+	if ( ber == NULL ) {
+		rs->sr_text = "internal error";
+		return LDAP_OTHER;
+	}
+
+	tag = ber_scanf( ber, "{im}", &size, &cookie );
+
+	/* Tested by frontend */
+	assert( tag != LBER_ERROR );
+	assert( size >= 0 );
+
+	/* cookie decoding/checks deferred to backend... */
+	if ( cookie.bv_len ) {
+		PagedResultsCookie reqcookie;
+		if( cookie.bv_len != sizeof( reqcookie ) ) {
+			/* bad cookie */
+			rs->sr_text = "paged results cookie is invalid";
+			rc = LDAP_PROTOCOL_ERROR;
+			goto done;
+		}
+
+		AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie ));
+
+		if ( reqcookie > ps->ps_cookie ) {
+			/* bad cookie */
+			rs->sr_text = "paged results cookie is invalid";
+			rc = LDAP_PROTOCOL_ERROR;
+			goto done;
+
+		} else if ( reqcookie < ps->ps_cookie ) {
+			rs->sr_text = "paged results cookie is invalid or old";
+			rc = LDAP_UNWILLING_TO_PERFORM;
+			goto done;
+		}
+
+	} else {
+		/* Initial request.  Initialize state. */
+#if 0
+		if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) {
+			/* There's another pagedResults control on the
+			 * same connection; reject new pagedResults controls 
+			 * (allowed by RFC2696) */
+			rs->sr_text = "paged results cookie unavailable; try later";
+			rc = LDAP_UNWILLING_TO_PERFORM;
+			goto done;
+		}
+#endif
+		ps->ps_cookie = 0;
+		ps->ps_count = 0;
+	}
+
+done:;
+	(void)ber_free( ber, 1 );
+
+	return rc;
+}
+
+/* This function is copied nearly verbatim from back-bdb/search.c */
+static void
+send_paged_response( 
+	Operation	*op,
+	SlapReply	*rs,
+	unsigned long	*lastid )
+{
+	LDAPControl	ctrl, *ctrls[2];
+	BerElementBuffer berbuf;
+	BerElement	*ber = (BerElement *)&berbuf;
+	PagedResultsCookie respcookie;
+	struct berval cookie;
+
+	Debug(LDAP_DEBUG_ARGS,
+		"send_paged_response: lastid=0x%08lx nentries=%d\n", 
+		lastid ? *lastid : 0, rs->sr_nentries, NULL );
+
+	BER_BVZERO( &ctrl.ldctl_value );
+	ctrls[0] = &ctrl;
+	ctrls[1] = NULL;
+
+	ber_init2( ber, NULL, LBER_USE_DER );
+
+	if ( lastid ) {
+		respcookie = ( PagedResultsCookie )(*lastid);
+		cookie.bv_len = sizeof( respcookie );
+		cookie.bv_val = (char *)&respcookie;
+
+	} else {
+		respcookie = ( PagedResultsCookie )0;
+		BER_BVSTR( &cookie, "" );
+	}
+
+	op->o_conn->c_pagedresults_state.ps_cookie = respcookie;
+	op->o_conn->c_pagedresults_state.ps_count =
+		((PagedResultsState *)op->o_pagedresults_state)->ps_count +
+		rs->sr_nentries;
+
+	/* return size of 0 -- no estimate */
+	ber_printf( ber, "{iO}", 0, &cookie ); 
+
+	if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) {
+		goto done;
+	}
+
+	ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
+	ctrls[0]->ldctl_iscritical = 0;
+
+	rs->sr_ctrls = ctrls;
+	rs->sr_err = LDAP_SUCCESS;
+	send_ldap_result( op, rs );
+	rs->sr_ctrls = NULL;
+
+done:
+	(void) ber_free_buf( ber );
+}
diff --git a/tests/data/sql-read.out b/tests/data/sql-read.out
index a88f3192b0..8167cc3e56 100644
--- a/tests/data/sql-read.out
+++ b/tests/data/sql-read.out
@@ -6,6 +6,12 @@ o: Example
 dc: example
 
 # Testing onelevel search...
+dn: cn=Akakiy Zinberstein,dc=example,dc=com
+objectClass: inetOrgPerson
+cn: Akakiy Zinberstein
+sn: Zinberstein
+givenName: Akakiy
+
 dn: documentTitle=book1,dc=example,dc=com
 objectClass: document
 description: abstract1
@@ -21,8 +27,6 @@ documentTitle: book2
 documentAuthor: cn=Mitya Kovalev,dc=example,dc=com
 documentIdentifier: document 2
 
-# refldap://localhost:9012/dc=example,dc=com??one
-
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -41,13 +45,15 @@ seeAlso: documentTitle=book1,dc=example,dc=com
 givenName: Torvlobnor
 telephoneNumber: 545-4563
 
+# refldap://localhost:9012/dc=example,dc=com??one
+
+# Testing subtree search...
 dn: cn=Akakiy Zinberstein,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Akakiy Zinberstein
 sn: Zinberstein
 givenName: Akakiy
 
-# Testing subtree search...
 dn: documentTitle=book1,dc=example,dc=com
 objectClass: document
 description: abstract1
@@ -63,8 +69,6 @@ documentTitle: book2
 documentAuthor: cn=Mitya Kovalev,dc=example,dc=com
 documentIdentifier: document 2
 
-# refldap://localhost:9012/dc=example,dc=com??sub
-
 dn: dc=example,dc=com
 objectClass: organization
 objectClass: dcObject
@@ -89,13 +93,15 @@ seeAlso: documentTitle=book1,dc=example,dc=com
 givenName: Torvlobnor
 telephoneNumber: 545-4563
 
+# refldap://localhost:9012/dc=example,dc=com??sub
+
+# Testing subtree search with manageDSAit...
 dn: cn=Akakiy Zinberstein,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Akakiy Zinberstein
 sn: Zinberstein
 givenName: Akakiy
 
-# Testing subtree search with manageDSAit...
 dn: documentTitle=book1,dc=example,dc=com
 objectClass: document
 description: abstract1
@@ -111,12 +117,6 @@ documentTitle: book2
 documentAuthor: cn=Mitya Kovalev,dc=example,dc=com
 documentIdentifier: document 2
 
-dn: ou=Referral,dc=example,dc=com
-objectClass: referral
-objectClass: extensibleObject
-ou: Referral
-ref: ldap://localhost:9012/
-
 dn: dc=example,dc=com
 objectClass: organization
 objectClass: dcObject
@@ -133,6 +133,12 @@ givenName: Mitya
 telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
+dn: ou=Referral,dc=example,dc=com
+objectClass: referral
+objectClass: extensibleObject
+ou: Referral
+ref: ldap://localhost:9012/
+
 dn: cn=Torvlobnor Puzdoy,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Torvlobnor Puzdoy
@@ -141,16 +147,8 @@ seeAlso: documentTitle=book1,dc=example,dc=com
 givenName: Torvlobnor
 telephoneNumber: 545-4563
 
-dn: cn=Akakiy Zinberstein,dc=example,dc=com
-objectClass: inetOrgPerson
-cn: Akakiy Zinberstein
-sn: Zinberstein
-givenName: Akakiy
-
 # Testing invalid filter...
 # Testing exact search...
-# refldap://localhost:9012/dc=example,dc=com??sub
-
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -161,9 +159,9 @@ givenName: Mitya
 telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
-# Testing substrings initial search...
 # refldap://localhost:9012/dc=example,dc=com??sub
 
+# Testing substrings initial search...
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -174,9 +172,9 @@ givenName: Mitya
 telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
-# Testing substrings any search...
 # refldap://localhost:9012/dc=example,dc=com??sub
 
+# Testing substrings any search...
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -187,9 +185,9 @@ givenName: Mitya
 telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
-# Testing substrings final search...
 # refldap://localhost:9012/dc=example,dc=com??sub
 
+# Testing substrings final search...
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -200,9 +198,9 @@ givenName: Mitya
 telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
-# Testing approx search...
 # refldap://localhost:9012/dc=example,dc=com??sub
 
+# Testing approx search...
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -213,9 +211,9 @@ givenName: Mitya
 telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
-# Testing extensible filter search...
 # refldap://localhost:9012/dc=example,dc=com??sub
 
+# Testing extensible filter search...
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -226,9 +224,9 @@ givenName: Mitya
 telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
-# Testing search for telephoneNumber...
 # refldap://localhost:9012/dc=example,dc=com??sub
 
+# Testing search for telephoneNumber...
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -239,9 +237,9 @@ givenName: Mitya
 telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
-# Testing AND search...
 # refldap://localhost:9012/dc=example,dc=com??sub
 
+# Testing AND search...
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -252,6 +250,8 @@ givenName: Mitya
 telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
+# refldap://localhost:9012/dc=example,dc=com??sub
+
 # Testing AND search on objectClass...
 dn: dc=example,dc=com
 objectClass: organization
@@ -260,8 +260,6 @@ o: Example
 dc: example
 
 # Testing OR search...
-# refldap://localhost:9012/dc=example,dc=com??sub
-
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -272,6 +270,8 @@ givenName: Mitya
 telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
+# refldap://localhost:9012/dc=example,dc=com??sub
+
 # Testing OR search on objectClass...
 dn: documentTitle=book1,dc=example,dc=com
 objectClass: document
@@ -295,6 +295,12 @@ o: Example
 dc: example
 
 # Testing NOT search...
+dn: cn=Akakiy Zinberstein,dc=example,dc=com
+objectClass: inetOrgPerson
+cn: Akakiy Zinberstein
+sn: Zinberstein
+givenName: Akakiy
+
 dn: cn=Torvlobnor Puzdoy,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Torvlobnor Puzdoy
@@ -303,12 +309,6 @@ seeAlso: documentTitle=book1,dc=example,dc=com
 givenName: Torvlobnor
 telephoneNumber: 545-4563
 
-dn: cn=Akakiy Zinberstein,dc=example,dc=com
-objectClass: inetOrgPerson
-cn: Akakiy Zinberstein
-sn: Zinberstein
-givenName: Akakiy
-
 # Testing NOT search on objectClass...
 dn: documentTitle=book1,dc=example,dc=com
 objectClass: document
@@ -325,15 +325,21 @@ documentTitle: book2
 documentAuthor: cn=Mitya Kovalev,dc=example,dc=com
 documentIdentifier: document 2
 
-# refldap://localhost:9012/dc=example,dc=com??sub
-
 dn: dc=example,dc=com
 objectClass: organization
 objectClass: dcObject
 o: Example
 dc: example
 
+# refldap://localhost:9012/dc=example,dc=com??sub
+
 # Testing NOT search on "auxiliary" objectClass...
+dn: cn=Akakiy Zinberstein,dc=example,dc=com
+objectClass: inetOrgPerson
+cn: Akakiy Zinberstein
+sn: Zinberstein
+givenName: Akakiy
+
 dn: documentTitle=book1,dc=example,dc=com
 objectClass: document
 description: abstract1
@@ -349,8 +355,6 @@ documentTitle: book2
 documentAuthor: cn=Mitya Kovalev,dc=example,dc=com
 documentIdentifier: document 2
 
-# refldap://localhost:9012/dc=example,dc=com??sub
-
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -369,11 +373,7 @@ seeAlso: documentTitle=book1,dc=example,dc=com
 givenName: Torvlobnor
 telephoneNumber: 545-4563
 
-dn: cn=Akakiy Zinberstein,dc=example,dc=com
-objectClass: inetOrgPerson
-cn: Akakiy Zinberstein
-sn: Zinberstein
-givenName: Akakiy
+# refldap://localhost:9012/dc=example,dc=com??sub
 
 # Testing attribute inheritance in filter...
 dn: dc=example,dc=com
@@ -383,15 +383,21 @@ o: Example
 dc: example
 
 # Testing undefined attribute in filter...
-# refldap://localhost:9012/dc=example,dc=com??sub
-
 dn: dc=example,dc=com
 objectClass: organization
 objectClass: dcObject
 o: Example
 dc: example
 
+# refldap://localhost:9012/dc=example,dc=com??sub
+
 # Testing objectClass inheritance in filter...
+dn: cn=Akakiy Zinberstein,dc=example,dc=com
+objectClass: inetOrgPerson
+cn: Akakiy Zinberstein
+sn: Zinberstein
+givenName: Akakiy
+
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
 cn: Mitya Kovalev
@@ -410,12 +416,6 @@ seeAlso: documentTitle=book1,dc=example,dc=com
 givenName: Torvlobnor
 telephoneNumber: 545-4563
 
-dn: cn=Akakiy Zinberstein,dc=example,dc=com
-objectClass: inetOrgPerson
-cn: Akakiy Zinberstein
-sn: Zinberstein
-givenName: Akakiy
-
 # Testing "auxiliary" objectClass in filter...
 dn: dc=example,dc=com
 objectClass: organization
@@ -424,14 +424,14 @@ o: Example
 dc: example
 
 # Testing hasSubordinates in filter...
-# refldap://localhost:9012/dc=example,dc=com??sub
-
 dn: dc=example,dc=com
 objectClass: organization
 objectClass: dcObject
 o: Example
 dc: example
 
+# refldap://localhost:9012/dc=example,dc=com??sub
+
 # Testing entryUUID in filter...
 dn: cn=Mitya Kovalev,dc=example,dc=com
 objectClass: inetOrgPerson
@@ -444,22 +444,23 @@ telephoneNumber: 222-3234
 telephoneNumber: 332-2334
 
 # Testing attribute inheritance in requested attributes...
-# refldap://localhost:9012/dc=example,dc=com??sub
-
 dn: cn=Mitya Kovalev,dc=example,dc=com
 cn: Mitya Kovalev
 sn: Kovalev
 givenName: Mitya
 
+# refldap://localhost:9012/dc=example,dc=com??sub
+
 # Testing objectClass in requested attributes...
+dn: cn=Akakiy Zinberstein,dc=example,dc=com
+objectClass: inetOrgPerson
+
 dn: documentTitle=book1,dc=example,dc=com
 objectClass: document
 
 dn: documentTitle=book2,dc=example,dc=com
 objectClass: document
 
-# refldap://localhost:9012/dc=example,dc=com??sub
-
 dn: dc=example,dc=com
 objectClass: organization
 objectClass: dcObject
@@ -470,10 +471,16 @@ objectClass: inetOrgPerson
 dn: cn=Torvlobnor Puzdoy,dc=example,dc=com
 objectClass: inetOrgPerson
 
-dn: cn=Akakiy Zinberstein,dc=example,dc=com
-objectClass: inetOrgPerson
+# refldap://localhost:9012/dc=example,dc=com??sub
 
 # Testing operational attributes in request...
+dn: cn=Akakiy Zinberstein,dc=example,dc=com
+structuralObjectClass: inetOrgPerson
+entryDN: cn=Akakiy Zinberstein,dc=example,dc=com
+subschemaSubentry: cn=Subschema
+hasSubordinates: FALSE
+entryUUID: 00000001-0000-0003-0000-000000000000
+
 dn: documentTitle=book1,dc=example,dc=com
 structuralObjectClass: document
 entryDN: documentTitle=book1,dc=example,dc=com
@@ -488,8 +495,6 @@ subschemaSubentry: cn=Subschema
 hasSubordinates: FALSE
 entryUUID: 00000002-0000-0002-0000-000000000000
 
-# refldap://localhost:9012/dc=example,dc=com??sub
-
 dn: dc=example,dc=com
 structuralObjectClass: organization
 entryDN: dc=example,dc=com
@@ -511,10 +516,5 @@ subschemaSubentry: cn=Subschema
 hasSubordinates: FALSE
 entryUUID: 00000001-0000-0002-0000-000000000000
 
-dn: cn=Akakiy Zinberstein,dc=example,dc=com
-structuralObjectClass: inetOrgPerson
-entryDN: cn=Akakiy Zinberstein,dc=example,dc=com
-subschemaSubentry: cn=Subschema
-hasSubordinates: FALSE
-entryUUID: 00000001-0000-0003-0000-000000000000
+# refldap://localhost:9012/dc=example,dc=com??sub
 
diff --git a/tests/scripts/sql-test000-read b/tests/scripts/sql-test000-read
index 8c70395166..d899763d36 100755
--- a/tests/scripts/sql-test000-read
+++ b/tests/scripts/sql-test000-read
@@ -79,7 +79,8 @@ fi
 
 echo "Testing baseobject search..."
 echo "# Testing baseobject search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -s base -S "" \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -90,7 +91,8 @@ fi
 
 echo "Testing onelevel search..."
 echo "# Testing onelevel search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -s one >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -s one -S "" \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -101,7 +103,8 @@ fi
 
 echo "Testing subtree search..."
 echo "# Testing subtree search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -112,7 +115,8 @@ fi
 
 echo "Testing subtree search with manageDSAit..."
 echo "# Testing subtree search with manageDSAit..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -M '*' ref >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -M -S "" '*' ref \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -123,8 +127,8 @@ fi
 
 echo "Testing invalid filter..."
 echo "# Testing invalid filter..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
-	 "(foo=)" >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" "(foo=)" \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -135,8 +139,8 @@ fi
 
 echo "Testing exact search..."
 echo "# Testing exact search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
-	 "(sn=Kovalev)" >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" "(sn=Kovalev)" \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -147,8 +151,8 @@ fi
 
 echo "Testing substrings initial search..."
 echo "# Testing substrings initial search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
-	 "(cn=m*)" >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" "(cn=m*)" \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -159,8 +163,8 @@ fi
 
 echo "Testing substrings any search..."
 echo "# Testing substrings any search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
-	 "(cn=*m*)" >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" "(cn=*m*)" \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -171,8 +175,8 @@ fi
 
 echo "Testing substrings final search..."
 echo "# Testing substrings final search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
-	 "(cn=*v)" >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" "(cn=*v)" \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -183,8 +187,8 @@ fi
 
 echo "Testing approx search..."
 echo "# Testing approx search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
-	 "(sn~=kovalev)" >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" "(sn~=kovalev)" \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -195,7 +199,7 @@ fi
 
 echo "Testing extensible filter search..."
 echo "# Testing extensible filter search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(sn:caseExactMatch:=Kovalev)" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -207,7 +211,7 @@ fi
 
 echo "Testing search for telephoneNumber..."
 echo "# Testing search for telephoneNumber..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(telephoneNumber=3322334)" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -219,7 +223,7 @@ fi
 
 echo "Testing AND search..."
 echo "# Testing AND search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(&(sn=kovalev)(givenName=mitya))" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -231,7 +235,7 @@ fi
 
 echo "Testing AND search on objectClass..."
 echo "# Testing AND search on objectClass..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(&(objectClass=organization)(objectClass=dcObject))" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -243,7 +247,7 @@ fi
 
 echo "Testing OR search..."
 echo "# Testing OR search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(|(sn=kovalev)(givenName=mitya))" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -255,8 +259,9 @@ fi
 
 echo "Testing OR search on objectClass..."
 echo "# Testing OR search on objectClass..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
-	 "(|(objectClass=document)(objectClass=organization))" >> $SEARCHOUT 2>&1
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
+	 "(|(objectClass=document)(objectClass=organization))" \
+	>> $SEARCHOUT 2>&1
 
 RC=$?
 if test $RC != 0 ; then
@@ -267,7 +272,7 @@ fi
 
 echo "Testing NOT search..."
 echo "# Testing NOT search..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 '(!(sn=kovalev))' >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -279,7 +284,7 @@ fi
 
 echo "Testing NOT search on objectClass..."
 echo "# Testing NOT search on objectClass..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 '(!(objectClass=inetOrgPerson))' >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -291,7 +296,7 @@ fi
 
 echo "Testing NOT search on \"auxiliary\" objectClass..."
 echo "# Testing NOT search on \"auxiliary\" objectClass..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 '(!(objectClass=dcObject))' >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -304,7 +309,7 @@ fi
 #### Needs work...
 echo "Testing NOT presence search... (disabled)"
 ###echo "# Testing NOT presence search..." >> $SEARCHOUT
-###$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+###$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 ###	 '(!(sn=*))' >> $SEARCHOUT 2>&1
 ###
 ###RC=$?
@@ -316,7 +321,7 @@ echo "Testing NOT presence search... (disabled)"
 
 echo "Testing attribute inheritance in filter..."
 echo "# Testing attribute inheritance in filter..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(name=example)" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -329,7 +334,7 @@ fi
 # ITS#4604
 echo "Testing undefined attribute in filter..."
 echo "# Testing undefined attribute in filter..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(|(o=example)(foobar=x))" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -341,7 +346,7 @@ fi
 
 echo "Testing objectClass inheritance in filter..."
 echo "# Testing objectClass inheritance in filter..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(objectClass=person)" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -353,7 +358,7 @@ fi
 
 echo "Testing \"auxiliary\" objectClass in filter..."
 echo "# Testing \"auxiliary\" objectClass in filter..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(objectClass=dcObject)" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -365,7 +370,7 @@ fi
 
 echo "Testing hasSubordinates in filter..."
 echo "# Testing hasSubordinates in filter..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(hasSubordinates=TRUE)" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -377,7 +382,7 @@ fi
 
 echo "Testing entryUUID in filter..."
 echo "# Testing entryUUID in filter..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(entryUUID=00000001-0000-0001-0000-000000000000)" >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -389,7 +394,7 @@ fi
 
 echo "Testing attribute inheritance in requested attributes..."
 echo "# Testing attribute inheritance in requested attributes..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 "(sn=kovalev)" name >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -401,7 +406,7 @@ fi
 
 echo "Testing objectClass in requested attributes..."
 echo "# Testing objectClass in requested attributes..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 objectClass >> $SEARCHOUT 2>&1
 
 RC=$?
@@ -413,7 +418,7 @@ fi
 
 echo "Testing operational attributes in request..."
 echo "# Testing operational attributes in request..." >> $SEARCHOUT
-$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -S "" \
 	 '+' 2>&1 > $SEARCHFLT
 
 RC=$?
-- 
GitLab