]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/search.c
Fixup bdb_entry_release now that entry_decode uses two memory blocks
[openldap] / servers / slapd / back-sql / search.c
1 /*
2  *       Copyright 1999, Dmitry Kovalev <mit@openldap.org>, All rights reserved.
3  *
4  *       Redistribution and use in source and binary forms are permitted only
5  *       as authorized by the OpenLDAP Public License.  A copy of this
6  *       license is available at http://www.OpenLDAP.org/license.html or
7  *       in file LICENSE in the top-level directory of the distribution.
8  */
9
10 #include "portable.h"
11
12 #ifdef SLAPD_SQL
13
14 #include <stdio.h>
15 #include <sys/types.h>
16 #include <string.h>
17 #include "slap.h"
18 #include "back-sql.h"
19 #include "sql-wrap.h"
20 #include "schema-map.h"
21 #include "entry-id.h"
22 #include "util.h"
23
24 int backsql_attrlist_add(backsql_srch_info *bsi,char *at_name)
25 {
26  char **p=bsi->attrs;
27  int n_attrs=0;
28
29  if (bsi->attrs==NULL)
30   return 1;
31
32  while(*p)
33  {
34   Debug(LDAP_DEBUG_TRACE,"==>backsql_attrlist_add(): attribute '%s' is in list\n",*p,0,0);
35   if (!strcasecmp(*p,at_name))
36    return 1;
37   n_attrs++;
38   p++;
39  }
40  Debug(LDAP_DEBUG_TRACE,"==>backsql_attrlist_add(): adding '%s' to list\n",at_name,0,0);
41  bsi->attrs=(char**)ch_realloc(bsi->attrs,(n_attrs+2)*sizeof(char*));
42  bsi->attrs[n_attrs]=ch_strdup(at_name);
43  bsi->attrs[n_attrs+1]=NULL;
44  return 1;
45 }
46
47 void backsql_init_search(backsql_srch_info *bsi,backsql_info *bi,char *nbase,int scope,
48                                                  int slimit,int tlimit,time_t stoptime,Filter *filter,
49                                                  SQLHDBC dbh,BackendDB *be,Connection *conn,Operation *op,char **attrs)
50 {
51  char **p;
52  bsi->base_dn=nbase;
53  bsi->scope=scope;
54  bsi->slimit=slimit;
55  bsi->tlimit=tlimit;
56  bsi->filter=filter;
57  bsi->dbh=dbh;
58  bsi->be=be;
59  bsi->conn=conn;
60  bsi->op=op;
61  if (attrs!=NULL)
62  {
63   bsi->attrs=(char**)ch_calloc(1,sizeof(char*));
64   bsi->attrs[0]=NULL;
65   for(p=attrs;*p!=NULL;p++)
66    backsql_attrlist_add(bsi,*p);
67  }
68  else
69   bsi->attrs=attrs;
70  bsi->abandon=0;
71  bsi->id_list=NULL;
72  bsi->stoptime=stoptime;
73  bsi->bi=bi;
74  bsi->sel=NULL; bsi->from=NULL; bsi->join_where=NULL; bsi->flt_where=NULL;
75  bsi->sel_len=0; bsi->from_len=0; bsi->jwhere_len=0; bsi->fwhere_len=0;
76 }
77
78 int backsql_process_filter_list(backsql_srch_info *bsi,Filter *f,int op)
79 {
80  char *sub_clause=NULL;
81  int len=0,res;
82
83  if (!f)
84   return 0;
85  bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",NULL);
86  while(1)
87  {
88   res=backsql_process_filter(bsi,f);
89   if (res < 0)
90     return -1;    /* TimesTen : If the query has no answers,
91                    don't bother to run the query. */
92  
93   f=f->f_next;
94   if (f==NULL)
95    break;
96
97   switch (op)
98   {
99    case LDAP_FILTER_AND:
100                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," AND ",NULL);
101                         break;
102    case LDAP_FILTER_OR:
103                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," OR ",NULL);
104                         break;
105   }
106  }
107
108  
109  bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,")",NULL);
110  return 1;
111 }
112
113 int backsql_process_sub_filter(backsql_srch_info *bsi,Filter *f)
114 {
115  int i;
116  backsql_at_map_rec *at=backsql_at_with_name(bsi->oc,f->f_sub_desc->ad_cname.bv_val);
117  
118  if (!f)
119   return 0;
120
121  bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",NULL);
122  /* TimesTen*/
123  Debug(LDAP_DEBUG_TRACE,"expr: '%s' '%s'\n",at->sel_expr,
124        at->sel_expr_u?at->sel_expr_u:"<NULL>",0);
125  if (bsi->bi->upper_func)
126  {
127    /* If a pre-upper-cased version of the column exists, use it. */
128    if (at->sel_expr_u) {
129      bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,
130                    at->sel_expr_u," LIKE '",NULL);
131    }
132    else {
133       bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,
134              bsi->bi->upper_func,"(",at->sel_expr,")",
135                  " LIKE '",NULL);
136    }
137  }
138  else
139  {
140   bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,at->sel_expr,
141                                 " LIKE '",NULL);
142  }
143  if (f->f_sub_initial!=NULL)
144  {
145   if (bsi->bi->upper_func)
146    {
147     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,ldap_pvt_str2upper(f->f_sub_initial->bv_val),NULL);
148    }
149    else
150     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_initial->bv_val,NULL);
151  }
152
153  bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"%",NULL);
154
155  if (f->f_sub_any!=NULL)
156   for(i=0;f->f_sub_any[i]!=NULL;i++)
157   {
158    /*Debug(LDAP_DEBUG_TRACE,"==>backsql_process_sub_filter(): sub_any='%s'\n",f->f_sub_any[i]->bv_val,0,0);*/
159    if (bsi->bi->upper_func)
160    {
161     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,ldap_pvt_str2upper(f->f_sub_any[i]->bv_val),"%",NULL);
162    }
163    else
164     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_any[i]->bv_val,"%",NULL);    
165   }
166
167  if (f->f_sub_final!=NULL)
168   if (bsi->bi->upper_func)
169    {
170     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,ldap_pvt_str2upper(f->f_sub_final->bv_val),NULL);
171    }
172    else
173     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_final->bv_val,NULL);
174
175  bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"')",NULL);
176  
177  return 1;
178 }
179
180 int backsql_process_filter(backsql_srch_info *bsi,Filter *f)
181 {
182  backsql_at_map_rec *at;
183  backsql_at_map_rec oc_attr={"objectClass","","",NULL,NULL,NULL,NULL};
184  char *at_name=NULL;
185  int done=0,len=0;
186  int rc=0; /* TimesTen */
187
188  Debug(LDAP_DEBUG_TRACE,"==>backsql_process_filter()\n",0,0,0);
189  if (f==NULL || f->f_choice==SLAPD_FILTER_COMPUTED)
190   {
191    return 0;
192   }
193   
194  switch(f->f_choice)
195  {
196   case LDAP_FILTER_OR:
197                         rc = backsql_process_filter_list(bsi,f->f_or,LDAP_FILTER_OR);
198                         done=1;
199                         break;
200   case LDAP_FILTER_AND:
201                         rc = backsql_process_filter_list(bsi,f->f_and,LDAP_FILTER_AND);
202                         done=1;
203                         break;
204   case LDAP_FILTER_NOT:
205                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"NOT (",NULL);
206                         rc = backsql_process_filter(bsi,f->f_not);
207                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,")",NULL);
208                         done=1;
209                         break;
210   case LDAP_FILTER_PRESENT:
211                         at_name=f->f_desc->ad_cname.bv_val;
212                         break;
213   default:
214                          at_name=f->f_av_desc->ad_cname.bv_val;
215                         break;
216  }
217
218  if (rc == -1)
219    goto impossible;     /* TimesTen : Don't run the query */
220  
221  if (done)
222   goto done;
223
224  if (strcasecmp(at_name,"objectclass"))
225   at=backsql_at_with_name(bsi->oc,at_name);
226  else
227  {
228   at=&oc_attr;
229   at->sel_expr=backsql_strcat(at->sel_expr,&len,"'",bsi->oc->name,"'",NULL);
230  }
231  if (at==NULL)
232  {
233   Debug(LDAP_DEBUG_TRACE,"backsql_process_filter(): attribute '%s' is not defined for objectclass '%s'\n",
234                       at_name,bsi->oc->name,0);
235   bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," 1=0 ",NULL);
236   goto impossible;
237  }
238                         
239  backsql_merge_from_clause(&bsi->from,&bsi->from_len,at->from_tbls);
240  /*need to add this attribute to list of attrs to load, so that we could do test_filter() later*/
241  backsql_attrlist_add(bsi,at_name);
242
243  if (at->join_where != NULL && strstr(bsi->join_where,at->join_where)==NULL)
244   bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len," AND ",at->join_where,NULL);
245
246  /*if (at!=&oc_attr)
247   bsi->sel=backsql_strcat(bsi->sel,&bsi->sel_len,",",at->sel_expr," AS ",at->name,NULL);
248  */
249
250  switch(f->f_choice)
251  {
252   case LDAP_FILTER_EQUALITY:
253                         /*maybe we should check type of at->sel_expr here somehow,
254                         * to know whether upper_func is applicable, but for now
255                         * upper_func stuff is made for Oracle, where UPPER is
256                         * safely applicable to NUMBER etc.
257                         */
258                         if (bsi->bi->upper_func) {
259                                 if (at->sel_expr_u)
260                                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",
261                       at->sel_expr_u,"='",
262                       ldap_pvt_str2upper(f->f_av_value->bv_val),"')",
263                       NULL);
264                         else
265                                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",
266                                         bsi->bi->upper_func,"(",at->sel_expr,")='",
267                                         ldap_pvt_str2upper(f->f_av_value->bv_val),"')",NULL);
268                         }
269                         else
270                          bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,"='",
271                                                         f->f_av_value->bv_val,"')",NULL);
272
273                         break;
274   case LDAP_FILTER_GE:
275                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,">=",
276                                                         f->f_av_value->bv_val,")",NULL);
277
278                         break;
279   case LDAP_FILTER_LE:
280                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,"<=",
281                                                         f->f_av_value->bv_val,")",NULL);
282                         break;
283   case LDAP_FILTER_PRESENT:
284                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"NOT (",at->sel_expr,
285                                                 " IS NULL)",NULL);
286                         break;
287   case LDAP_FILTER_SUBSTRINGS:
288                         backsql_process_sub_filter(bsi,f);
289                         break;
290  }
291
292 done:
293  if (oc_attr.sel_expr!=NULL)
294   free(oc_attr.sel_expr);
295  Debug(LDAP_DEBUG_TRACE,"<==backsql_process_filter()\n",0,0,0);
296  return 1;
297
298 impossible:
299  if (oc_attr.sel_expr!=NULL)
300   free(oc_attr.sel_expr);
301  Debug(LDAP_DEBUG_TRACE,"<==backsql_process_filter() returns -1\n",0,0,0);
302  return -1;
303
304 }
305
306 char* backsql_srch_query(backsql_srch_info *bsi)
307 {
308  char *query=NULL;
309  int q_len=0;
310  int rc;
311
312  Debug(LDAP_DEBUG_TRACE,"==>backsql_srch_query()\n",0,0,0);
313  bsi->sel=NULL;
314  bsi->from=NULL;
315  bsi->join_where=NULL;
316  bsi->flt_where=NULL;
317  bsi->sel_len=bsi->from_len=bsi->jwhere_len=bsi->fwhere_len=0;
318
319  bsi->sel=backsql_strcat(bsi->sel,&bsi->sel_len,
320                                 "SELECT DISTINCT ldap_entries.id,",bsi->oc->keytbl,".",bsi->oc->keycol,
321                                 ", '",bsi->oc->name,"' AS objectClass",
322                                 ", ldap_entries.dn AS dn",
323                                 NULL);
324  bsi->from=backsql_strcat(bsi->from,&bsi->from_len," FROM ldap_entries,",bsi->oc->keytbl,NULL);
325  bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len," WHERE ",
326          bsi->oc->keytbl,".",bsi->oc->keycol,"=ldap_entries.keyval AND ",
327          "ldap_entries.oc_map_id=? AND ",NULL);
328
329  switch(bsi->scope)
330  {
331   case LDAP_SCOPE_BASE:
332         if (bsi->bi->upper_func)
333                  {
334                   bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
335                          bsi->bi->upper_func,"(","ldap_entries.dn)=(?)",NULL);
336                  }
337                 else
338                  {
339                   bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
340                                 "ldap_entries.dn=?",NULL);
341                  }
342                 break;
343   case LDAP_SCOPE_ONELEVEL:
344                 bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
345                                 "ldap_entries.parent=?",NULL);
346                 break;
347   case LDAP_SCOPE_SUBTREE:
348                 bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
349                                 bsi->bi->subtree_cond,NULL);
350                 break;
351  }
352
353  rc = backsql_process_filter(bsi, bsi->filter);
354  if (rc>0) {
355   query=backsql_strcat(query,&q_len,bsi->sel,bsi->from,bsi->join_where," AND ",bsi->flt_where,NULL);
356  }
357  else if (rc < 0) {
358     /* Indicates that there's no possible way the filter matches
359       anything.  No need to issue the query. */
360
361    Debug(LDAP_DEBUG_TRACE,"<==backsql_srch_query() returns NULL\n",0,0,0);
362    free(query);
363    query = NULL;
364  }
365  
366  free(bsi->sel);
367  free(bsi->from);
368  free(bsi->join_where);
369  free(bsi->flt_where);
370  bsi->sel_len=bsi->from_len=bsi->jwhere_len=bsi->fwhere_len=0;
371  Debug(LDAP_DEBUG_TRACE,"<==backsql_srch_query()\n",0,0,0);
372  return query;
373 }
374
375 int backsql_oc_get_candidates(backsql_oc_map_rec *oc,backsql_srch_info *bsi)
376 {
377  char *query=NULL;
378  SQLHSTMT sth;
379  RETCODE rc;
380  backsql_entryID base_id,*res,*c_id;
381  /*Entry *e;*/
382  BACKSQL_ROW_NTS row;
383  int i;
384  int j;
385  char temp_base_dn[BACKSQL_MAX_DN_LEN+1]; /* TimesTen*/
386  
387  Debug(LDAP_DEBUG_TRACE,"==>backsql_oc_get_candidates(): oc='%s'\n",oc->name,0,0);
388  bsi->oc=oc;
389  query=backsql_srch_query(bsi);
390  if (query==NULL)
391  {
392   Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): could not construct query for objectclass\n",0,0,0);
393   return 1;
394  }
395
396  Debug(LDAP_DEBUG_TRACE,"Constructed query: %s\n",query,0,0);
397
398  if ((rc=backsql_Prepare(bsi->dbh,&sth,query,0)) != SQL_SUCCESS)
399   {
400    Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error preparing query\n",0,0,0);
401    backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
402    free(query);
403    return 1;
404   }
405  free(query);
406
407  if (backsql_BindParamID(sth,1,&bsi->oc->id) != SQL_SUCCESS)
408  {
409   Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding objectclass id parameter\n",0,0,0);
410   return 1;
411  }
412  switch(bsi->scope)
413  {
414   case LDAP_SCOPE_BASE:
415                 if ((rc=backsql_BindParamStr(sth,2,bsi->base_dn,BACKSQL_MAX_DN_LEN)) != SQL_SUCCESS)
416                 {
417          Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding base_dn parameter\n",0,0,0);
418                  backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
419          return 1;
420                 }
421                 break;
422
423   case LDAP_SCOPE_SUBTREE:
424     /* Sets the parameters for the SQL built earlier */
425     /* NOTE that all the databases could actually use the TimesTen version,
426        which would be cleaner and would also eliminate the need for the
427        subtree_cond line in the configuration file.  For now, I'm leaving
428        it the way it is, so non-TimesTen databases use the original code.
429        But at some point this should get cleaned up. */
430      /* If "dn" is being used, do a suffix search.
431      If "dn_ru" is being used, do a prefix search. */
432
433     if (bsi->bi->has_ldapinfo_dn_ru) {
434        temp_base_dn[0] = '\0';
435        for ((i=0, j=strlen(bsi->base_dn)-1); j >= 0; (i++, j--)) {
436          *(temp_base_dn+i) = toupper(*(bsi->base_dn+j));
437        }
438        *(temp_base_dn+i) = '%';
439        *(temp_base_dn+i+1) = '\0';
440     }
441     else {
442         strcpy(temp_base_dn, "%");
443         for (i = 0; *(bsi->base_dn+i); i++) {
444           *(temp_base_dn+i+1) = toupper(*(bsi->base_dn+i));
445         }
446         *(temp_base_dn+i+1) = '\0';
447     }
448     Debug(LDAP_DEBUG_TRACE, "dn '%s'\n", temp_base_dn, 0, 0);
449
450     if ((rc=backsql_BindParamStr(sth,2,temp_base_dn,BACKSQL_MAX_DN_LEN)) !=
451 SQL_SUCCESS)
452     {
453          Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding base_dn parameter (2)\n",0,0,0);
454          backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
455          return 1;
456     }
457         break;
458
459   case LDAP_SCOPE_ONELEVEL:
460                 res=backsql_dn2id(bsi->bi,&base_id,bsi->dbh,bsi->base_dn);
461                 if (res==NULL)
462                 {
463                  Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): could not retrieve base_dn id - no such entry\n",0,0,0);
464                  bsi->status=LDAP_NO_SUCH_OBJECT;
465                  return 0;
466                 }
467                 if (backsql_BindParamID(sth,2,&base_id.id) != SQL_SUCCESS)
468                 {
469                  Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding base id parameter\n",0,0,0);
470                  free(base_id.dn);
471                  return 1;
472                 }               
473                 free(base_id.dn);
474                 break;
475  }
476  
477  if ((rc=SQLExecute(sth)) != SQL_SUCCESS && rc!= SQL_SUCCESS_WITH_INFO)
478   {
479    Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error executing query\n",0,0,0);
480    backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
481    SQLFreeStmt(sth,SQL_DROP);
482    return 1;
483   }
484
485  backsql_BindRowAsStrings(sth,&row);
486  while ((rc=SQLFetch(sth)) == SQL_SUCCESS || rc==SQL_SUCCESS_WITH_INFO)
487   {
488    /*
489    e=(Entry*)ch_calloc(1,sizeof(Entry)); 
490    for (i=1;i<row.ncols;i++)
491     {
492      if (row.is_null[i]>0)
493       {
494        backsql_entry_addattr(e,row.col_names[i],row.cols[i],row.col_prec[i]);
495        Debug(LDAP_DEBUG_TRACE,"prec=%d\n",(int)row.col_prec[i],0,0);
496       }
497      else
498       Debug(LDAP_DEBUG_TRACE,"NULL value in this row for attribute '%s'\n",row.col_names[i],0,0);
499     }
500    */
501
502    c_id=(backsql_entryID*)ch_calloc(1,sizeof(backsql_entryID));
503    c_id->id=atoi(row.cols[0]);
504    c_id->keyval=atoi(row.cols[1]);
505    c_id->oc_id=bsi->oc->id;
506    c_id->dn=ch_strdup(row.cols[3]);
507    c_id->next=bsi->id_list;
508    bsi->id_list=c_id;
509    Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): added entry id=%d, keyval=%d dn='%s'\n",
510                 c_id->id,c_id->keyval,row.cols[3]);
511   }
512  backsql_FreeRow(&row);
513  SQLFreeStmt(sth,SQL_DROP);
514
515  Debug(LDAP_DEBUG_TRACE,"<==backsql_oc_get_candidates()\n",0,0,0);
516  return 1;
517 }
518
519 int backsql_search(BackendDB *be,Connection *conn,Operation *op,
520         const char *base, const char *nbase, int scope,int deref,int slimit,int tlimit,
521         Filter *filter, const char *filterstr,char **attrs,int attrsonly)
522 {
523  backsql_info *bi=(backsql_info*)be->be_private;
524  SQLHDBC dbh;
525  int sres;
526  int nentries;
527  Entry *entry,*res;
528  int manageDSAit = get_manageDSAit( op );
529  struct berval **v2refs = NULL;
530  time_t stoptime;
531  backsql_srch_info srch_info;
532  backsql_entryID *eid=NULL;
533
534  Debug(LDAP_DEBUG_TRACE,"==>backsql_search(): base='%s', filter='%s', scope=%d,",
535                      nbase,filterstr,scope);
536  Debug(LDAP_DEBUG_TRACE," deref=%d, attrsonly=%d, attributes to load: %s\n",
537          deref,attrsonly,attrs==NULL?"all":"custom list");
538  dbh=backsql_get_db_conn(be,conn);
539
540  if (!dbh)
541  {
542   Debug(LDAP_DEBUG_TRACE,"backsql_search(): could not get connection handle - exiting\n",0,0,0);
543   send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
544   return 1;
545  }
546
547  /* TimesTen : Pass it along to the lower level routines */ 
548  srch_info.isTimesTen = bi->isTimesTen; 
549  
550  if (tlimit == 0 && be_isroot(be,op->o_dn))
551   {
552    tlimit = -1; /* allow root to set no limit */
553   } 
554  else
555   {
556    tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
557                     be->be_timelimit : tlimit;
558    stoptime = op->o_time + tlimit;
559   }
560   
561  if (slimit == 0 && be_isroot(be,op->o_dn))
562   {
563    slimit = -1; /* allow root to set no limit */
564   }
565  else
566   {
567    slimit = (slimit > be->be_sizelimit || slimit < 1) ?
568                     be->be_sizelimit : slimit;
569   }
570
571  backsql_init_search(&srch_info,bi,(char*)nbase,scope,slimit,tlimit,stoptime,filter,dbh,
572                  be,conn,op,attrs);
573
574  /*for each objectclass we try to construct query which gets IDs
575   *of entries matching LDAP query filter and scope (or at least candidates),
576   *and get the IDs
577 */
578  avl_apply(bi->oc_by_name,(AVL_APPLY)backsql_oc_get_candidates,&srch_info,0,AVL_INORDER);
579              
580  nentries=0;
581  /*now we load candidate entries (only those attrubutes mentioned in attrs and filter),
582   *test it against full filter and then send to client
583 */
584  for(eid=srch_info.id_list;eid!=NULL;eid=eid->next)
585   {
586    /* check for abandon */
587    ldap_pvt_thread_mutex_lock(&op->o_abandonmutex);
588    if (op->o_abandon)
589     {
590      ldap_pvt_thread_mutex_unlock(&op->o_abandonmutex);
591      break;
592     }
593    ldap_pvt_thread_mutex_unlock(&op->o_abandonmutex);
594
595    /* check time limit */
596    if ( tlimit != -1 && slap_get_time() > stoptime)
597     {
598          send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED,
599                                 NULL, NULL, v2refs, NULL, nentries );
600      
601      break;
602     }
603      
604    Debug(LDAP_DEBUG_TRACE,"backsql_search(): loading data for entry id=%d, oc_id=%d, keyval=%d\n",
605                eid->id,eid->oc_id,eid->keyval);
606    
607    entry=(Entry *)ch_calloc(sizeof(Entry),1);
608    res=backsql_id2entry(&srch_info,entry,eid);
609    if (res==NULL)
610     {
611      Debug(LDAP_DEBUG_TRACE,"backsql_search(): error in backsql_id2entry() - skipping entry\n",0,0,0);
612      continue;
613     }
614
615    if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
616                         is_entry_referral( entry ) )
617     {
618      struct berval **refs = get_entry_referrals(be,conn,op,entry);
619
620      send_search_reference( be, conn, op, entry, refs, scope, NULL, &v2refs );
621      ber_bvecfree( refs );
622      continue;
623     }
624
625    if (test_filter(be,conn,op,entry,filter)==LDAP_COMPARE_TRUE)
626     {
627      if ((sres=send_search_entry(be,conn,op,entry,attrs,attrsonly,NULL))==-1)
628       {
629        Debug(LDAP_DEBUG_TRACE,"backsql_search(): connection lost\n",0,0,0);
630        break;
631       }
632      nentries+=!sres;                                   
633     }
634    entry_free(entry);
635   }
636
637  for(eid=srch_info.id_list;eid!=NULL;eid=backsql_free_entryID(eid));
638
639  charray_free(srch_info.attrs);
640
641  if (nentries>0)
642   send_search_result( conn, op,
643                 v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
644                 NULL, NULL, v2refs, NULL, nentries );
645  else
646   send_ldap_result(conn,op,LDAP_NO_SUCH_OBJECT,NULL,NULL,NULL,0);
647  
648  Debug(LDAP_DEBUG_TRACE,"<==backsql_search()\n",0,0,0);
649  return 0;
650 }
651
652 #endif /* SLAPD_SQL */