backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
{
	backsql_info		*bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
	int			rc;

	assert( query != NULL );
	BER_BVZERO( query );

	bsi->bsi_use_subtree_shortcut = 0;

	Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n" );
	BER_BVZERO( &bsi->bsi_sel.bb_val );
	BER_BVZERO( &bsi->bsi_sel.bb_val );
	bsi->bsi_sel.bb_len = 0;
	BER_BVZERO( &bsi->bsi_from.bb_val );
	bsi->bsi_from.bb_len = 0;
	BER_BVZERO( &bsi->bsi_join_where.bb_val );
	bsi->bsi_join_where.bb_len = 0;
	BER_BVZERO( &bsi->bsi_flt_where.bb_val );
	bsi->bsi_flt_where.bb_len = 0;

	backsql_strfcat_x( &bsi->bsi_sel,
			bsi->bsi_op->o_tmpmemctx,
			"lbcbc",
			(ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ),
				"SELECT DISTINCT ldap_entries.id,", 
			&bsi->bsi_oc->bom_keytbl, 
			'.', 
			&bsi->bsi_oc->bom_keycol, 
			',' );

	if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
		backsql_strfcat_x( &bsi->bsi_sel,
				bsi->bsi_op->o_tmpmemctx,
				"blbl",
				&bi->sql_strcast_func, 
				(ber_len_t)STRLENOF( "('" /* ') */ ),
					"('" /* ') */ ,
				&bsi->bsi_oc->bom_oc->soc_cname,
				(ber_len_t)STRLENOF( /* (' */ "')" ),
					/* (' */ "')" );
	} else {
		backsql_strfcat_x( &bsi->bsi_sel,
				bsi->bsi_op->o_tmpmemctx,
				"cbc",
				'\'',
				&bsi->bsi_oc->bom_oc->soc_cname,
				'\'' );
	}

	backsql_strfcat_x( &bsi->bsi_sel,
			bsi->bsi_op->o_tmpmemctx,
			"b",
			&bi->sql_dn_oc_aliasing );
	backsql_strfcat_x( &bsi->bsi_from,
			bsi->bsi_op->o_tmpmemctx,
			"lb",
			(ber_len_t)STRLENOF( " FROM ldap_entries," ),
				" FROM ldap_entries,",
			&bsi->bsi_oc->bom_keytbl );

	backsql_strfcat_x( &bsi->bsi_join_where,
			bsi->bsi_op->o_tmpmemctx,
			"lbcbl",
			(ber_len_t)STRLENOF( " WHERE " ), " WHERE ",
			&bsi->bsi_oc->bom_keytbl,
			'.',
			&bsi->bsi_oc->bom_keycol,
			(ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ),
				"=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );

	switch ( bsi->bsi_scope ) {
	case LDAP_SCOPE_BASE:
		if ( BACKSQL_CANUPPERCASE( bi ) ) {
			backsql_strfcat_x( &bsi->bsi_join_where,
					bsi->bsi_op->o_tmpmemctx, 
					"bl",
					&bi->sql_upper_func,
					(ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ),
						"(ldap_entries.dn)=?" );
		} else {
			backsql_strfcat_x( &bsi->bsi_join_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
					(ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
						"ldap_entries.dn=?" );
		}
		break;
		
	case BACKSQL_SCOPE_BASE_LIKE:
		if ( BACKSQL_CANUPPERCASE( bi ) ) {
			backsql_strfcat_x( &bsi->bsi_join_where,
					bsi->bsi_op->o_tmpmemctx,
					"bl",
					&bi->sql_upper_func,
					(ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
						"(ldap_entries.dn) LIKE ?" );
		} else {
			backsql_strfcat_x( &bsi->bsi_join_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
					(ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
						"ldap_entries.dn LIKE ?" );
		}
		break;
		
	case LDAP_SCOPE_ONELEVEL:
		backsql_strfcat_x( &bsi->bsi_join_where,
				bsi->bsi_op->o_tmpmemctx,
				"l",
				(ber_len_t)STRLENOF( "ldap_entries.parent=?" ),
					"ldap_entries.parent=?" );
		break;

	case LDAP_SCOPE_SUBORDINATE:
	case LDAP_SCOPE_SUBTREE:
		if ( BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ) {
			int		i;
			BackendDB	*bd = bsi->bsi_op->o_bd;

			assert( bd->be_nsuffix != NULL );

			for ( i = 0; !BER_BVISNULL( &bd->be_nsuffix[ i ] ); i++ )
			{
				if ( dn_match( &bd->be_nsuffix[ i ],
							bsi->bsi_base_ndn ) )
				{
					/* pass this to the candidate selection
					 * routine so that the DN is not bound
					 * to the select statement */
					bsi->bsi_use_subtree_shortcut = 1;
					break;
				}
			}
		}

		if ( bsi->bsi_use_subtree_shortcut ) {
			/* Skip the base DN filter, as every entry will match it */
			backsql_strfcat_x( &bsi->bsi_join_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
					(ber_len_t)STRLENOF( "9=9"), "9=9");

		} else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) {
			/* This should always be true... */
			backsql_strfcat_x( &bsi->bsi_join_where,
					bsi->bsi_op->o_tmpmemctx,
					"b",
					&bi->sql_subtree_cond );

		} else if ( BACKSQL_CANUPPERCASE( bi ) ) {
			backsql_strfcat_x( &bsi->bsi_join_where,
					bsi->bsi_op->o_tmpmemctx,
					"bl",
					&bi->sql_upper_func,
					(ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
						"(ldap_entries.dn) LIKE ?"  );

		} else {
			backsql_strfcat_x( &bsi->bsi_join_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
					(ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
						"ldap_entries.dn LIKE ?" );
		}

		break;

	default:
		assert( 0 );
	}

#ifndef BACKSQL_ARBITRARY_KEY
	/* 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, sizeof( lowidstring ),
				" AND ldap_entries.id>%lu", lowid );
			backsql_strfcat_x( &bsi->bsi_join_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
					(ber_len_t)lowidlen,
					lowidstring );
		}
	}
#endif /* ! BACKSQL_ARBITRARY_KEY */

	rc = backsql_process_filter( bsi, bsi->bsi_filter );
	if ( rc > 0 ) {
		struct berbuf	bb = BB_NULL;

		backsql_strfcat_x( &bb,
				bsi->bsi_op->o_tmpmemctx,
				"bbblb",
				&bsi->bsi_sel.bb_val,
				&bsi->bsi_from.bb_val, 
				&bsi->bsi_join_where.bb_val,
				(ber_len_t)STRLENOF( " AND " ), " AND ",
				&bsi->bsi_flt_where.bb_val );

		*query = bb.bb_val;

	} else if ( rc < 0 ) {
		/* 
		 * Indicates that there's no possible way the filter matches
		 * anything.  No need to issue the query
		 */
		free( query->bv_val );
		BER_BVZERO( query );
	}
 
	bsi->bsi_op->o_tmpfree( bsi->bsi_sel.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
	BER_BVZERO( &bsi->bsi_sel.bb_val );
	bsi->bsi_sel.bb_len = 0;
	bsi->bsi_op->o_tmpfree( bsi->bsi_from.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
	BER_BVZERO( &bsi->bsi_from.bb_val );
	bsi->bsi_from.bb_len = 0;
	bsi->bsi_op->o_tmpfree( bsi->bsi_join_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
	BER_BVZERO( &bsi->bsi_join_where.bb_val );
	bsi->bsi_join_where.bb_len = 0;
	bsi->bsi_op->o_tmpfree( bsi->bsi_flt_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
	BER_BVZERO( &bsi->bsi_flt_where.bb_val );
	bsi->bsi_flt_where.bb_len = 0;
	
	Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n",
		query->bv_val ? query->bv_val : "NULL" );
	
	return ( rc <= 0 ? 1 : 0 );
}