]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/search.c
82db1e1cf8a30cbb374b7c2db1670f6476833cd3
[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   
90   f=f->f_next;
91   if (f==NULL)
92    break;
93
94   switch (op)
95   {
96    case LDAP_FILTER_AND:
97                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," AND ",NULL);
98                         break;
99    case LDAP_FILTER_OR:
100                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," OR ",NULL);
101                         break;
102   }
103  }
104
105  
106  bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,")",NULL);
107  return 1;
108 }
109
110 int backsql_process_sub_filter(backsql_srch_info *bsi,Filter *f)
111 {
112  int i;
113  backsql_at_map_rec *at=backsql_at_with_name(bsi->oc,f->f_sub_desc->ad_cname->bv_val);
114  
115  if (!f)
116   return 0;
117
118  bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",NULL);
119
120  if (bsi->bi->upper_func)
121  {
122   bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,
123           bsi->bi->upper_func,"(",at->sel_expr,")",
124                                 " LIKE '",NULL);
125  }
126  else
127  {
128   bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,at->sel_expr,
129                                 " LIKE '",NULL);
130  }
131  if (f->f_sub_initial!=NULL)
132  {
133   if (bsi->bi->upper_func)
134    {
135     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,toupper(f->f_sub_initial->bv_val),NULL);
136    }
137    else
138     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_initial->bv_val,NULL);
139  }
140
141  bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"%",NULL);
142
143  if (f->f_sub_any!=NULL)
144   for(i=0;f->f_sub_any[i]!=NULL;i++)
145   {
146    //Debug(LDAP_DEBUG_TRACE,"==>backsql_process_sub_filter(): sub_any='%s'\n",f->f_sub_any[i]->bv_val,0,0);
147    if (bsi->bi->upper_func)
148    {
149     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,toupper(f->f_sub_any[i]->bv_val),"%",NULL);
150    }
151    else
152     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_any[i]->bv_val,"%",NULL);    
153   }
154
155  if (f->f_sub_final!=NULL)
156   if (bsi->bi->upper_func)
157    {
158     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,toupper(f->f_sub_final->bv_val),NULL);
159    }
160    else
161     bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_final->bv_val,NULL);
162
163  bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"')",NULL);
164  
165  return 1;
166 }
167
168 int backsql_process_filter(backsql_srch_info *bsi,Filter *f)
169 {
170  backsql_at_map_rec *at;
171  backsql_at_map_rec oc_attr={"objectClass","","",NULL,NULL,NULL,NULL};
172  char *at_name=NULL;
173  int done=0,len=0;
174
175  Debug(LDAP_DEBUG_TRACE,"==>backsql_process_filter()\n",0,0,0);
176  if (f==NULL || f->f_choice==SLAPD_FILTER_COMPUTED)
177   {
178    return 0;
179   }
180   
181  switch(f->f_choice)
182  {
183   case LDAP_FILTER_OR:
184                         backsql_process_filter_list(bsi,f->f_or,LDAP_FILTER_OR);
185                         done=1;
186                         break;
187   case LDAP_FILTER_AND:
188                         backsql_process_filter_list(bsi,f->f_and,LDAP_FILTER_AND);
189                         done=1;
190                         break;
191   case LDAP_FILTER_NOT:
192                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"NOT (",NULL);
193                         backsql_process_filter(bsi,f->f_not);
194                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,")",NULL);
195                         done=1;
196                         break;
197   case LDAP_FILTER_PRESENT:
198                         at_name=f->f_desc->ad_cname->bv_val;
199                         break;
200   default:
201                          at_name=f->f_av_desc->ad_cname->bv_val;
202                         break;
203  }
204  
205  if (done)
206   goto done;
207
208  if (strcasecmp(at_name,"objectclass"))
209   at=backsql_at_with_name(bsi->oc,at_name);
210  else
211  {
212   at=&oc_attr;
213   at->sel_expr=backsql_strcat(at->sel_expr,&len,"'",bsi->oc->name,"'",NULL);
214  }
215  if (at==NULL)
216  {
217   Debug(LDAP_DEBUG_TRACE,"backsql_process_filter(): attribute '%s' is not defined for objectclass '%s'\n",
218                       at_name,bsi->oc->name,0);
219   bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," 1=0 ",NULL);
220   return -1;
221  }
222                         
223  backsql_merge_from_clause(&bsi->from,&bsi->from_len,at->from_tbls);
224  //need to add this attribute to list of attrs to load, so that we could do test_filter() later
225  backsql_attrlist_add(bsi,at_name);
226
227  if (at->join_where != NULL && strstr(bsi->join_where,at->join_where)==NULL)
228   bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len," AND ",at->join_where,NULL);
229
230  //if (at!=&oc_attr)
231  // bsi->sel=backsql_strcat(bsi->sel,&bsi->sel_len,",",at->sel_expr," AS ",at->name,NULL);
232
233  switch(f->f_choice)
234  {
235   case LDAP_FILTER_EQUALITY:
236                         //maybe we should check type of at->sel_expr here somehow,
237                         //to know whether upper_func is applicable, but for now
238                         //upper_func stuff is made for Oracle, where UPPER is
239                         //safely applicable to NUMBER etc.
240                         if (bsi->bi->upper_func)
241                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",
242                                         bsi->bi->upper_func,"(",at->sel_expr,")='",
243                                                 toupper(f->f_av_value->bv_val),"')",NULL);
244                         else
245                          bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,"='",
246                                                         f->f_av_value->bv_val,"')",NULL);
247
248                         break;
249   case LDAP_FILTER_GE:
250                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,">=",
251                                                         f->f_av_value->bv_val,")",NULL);
252
253                         break;
254   case LDAP_FILTER_LE:
255                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,"<=",
256                                                         f->f_av_value->bv_val,")",NULL);
257                         break;
258   case LDAP_FILTER_PRESENT:
259                         bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"NOT (",at->sel_expr,
260                                                 " IS NULL)",NULL);
261                         break;
262   case LDAP_FILTER_SUBSTRINGS:
263                         backsql_process_sub_filter(bsi,f);
264                         break;
265  }
266
267 done:
268  if (oc_attr.sel_expr!=NULL)
269   free(oc_attr.sel_expr);
270  Debug(LDAP_DEBUG_TRACE,"<==backsql_process_filter()\n",0,0,0);
271  return 1;
272 }
273
274 char* backsql_srch_query(backsql_srch_info *bsi)
275 {
276  char *query=NULL;
277  int q_len=0;
278
279  Debug(LDAP_DEBUG_TRACE,"==>backsql_srch_query()\n",0,0,0);
280  bsi->sel=NULL;
281  bsi->from=NULL;
282  bsi->join_where=NULL;
283  bsi->flt_where=NULL;
284  bsi->sel_len=bsi->from_len=bsi->jwhere_len=bsi->fwhere_len=0;
285
286  bsi->sel=backsql_strcat(bsi->sel,&bsi->sel_len,
287                                 "SELECT ldap_entries.id,",bsi->oc->keytbl,".",bsi->oc->keycol,
288                                 ", '",bsi->oc->name,"' AS objectClass",
289                                 ", ldap_entries.dn AS dn",
290                                 NULL);
291  bsi->from=backsql_strcat(bsi->from,&bsi->from_len," FROM ldap_entries,",bsi->oc->keytbl,NULL);
292  bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len," WHERE ",
293          bsi->oc->keytbl,".",bsi->oc->keycol,"=ldap_entries.keyval AND ",
294          "ldap_entries.oc_map_id=? AND ",NULL);
295
296  switch(bsi->scope)
297  {
298   case LDAP_SCOPE_BASE:
299         if (bsi->bi->upper_func)
300                  {
301                   bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
302                          bsi->bi->upper_func,"(","ldap_entries.dn)=(?)",NULL);
303                  }
304                 else
305                  {
306                   bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
307                                 "ldap_entries.dn=?",NULL);
308                  }
309                 break;
310   case LDAP_SCOPE_ONELEVEL:
311                 bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
312                                 "ldap_entries.parent=?",NULL);
313                 break;
314   case LDAP_SCOPE_SUBTREE:
315                 bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
316                                 bsi->bi->subtree_cond,NULL);
317                 break;
318  }
319  if (backsql_process_filter(bsi,bsi->filter))
320   query=backsql_strcat(query,&q_len,bsi->sel,bsi->from,bsi->join_where," AND ",bsi->flt_where,NULL);
321
322  
323  free(bsi->sel);
324  free(bsi->from);
325  free(bsi->join_where);
326  free(bsi->flt_where);
327  bsi->sel_len=bsi->from_len=bsi->jwhere_len=bsi->fwhere_len=0;
328  Debug(LDAP_DEBUG_TRACE,"<==backsql_srch_query()\n",0,0,0);
329  return query;
330 }
331
332 int backsql_oc_get_candidates(backsql_oc_map_rec *oc,backsql_srch_info *bsi)
333 {
334  char *query=NULL;
335  SQLHSTMT sth;
336  RETCODE rc;
337  backsql_entryID base_id,*res,*c_id;
338  //Entry *e;
339  BACKSQL_ROW_NTS row;
340  //int i;
341  
342  Debug(LDAP_DEBUG_TRACE,"==>backsql_oc_get_candidates(): oc='%s'\n",oc->name,0,0);
343  bsi->oc=oc;
344  query=backsql_srch_query(bsi);
345  if (query==NULL)
346  {
347   Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): could not construct query for objectclass\n",0,0,0);
348   return 1;
349  }
350
351  Debug(LDAP_DEBUG_TRACE,"Constructed query: %s\n",query,0,0);
352  if ((rc=backsql_Prepare(bsi->dbh,&sth,query,0)) != SQL_SUCCESS)
353   {
354    Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error preparing query\n",0,0,0);
355    backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
356    free(query);
357    return 1;
358   }
359  free(query);
360
361  if (backsql_BindParamID(sth,1,&bsi->oc->id) != SQL_SUCCESS)
362  {
363   Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding objectclass id parameter\n",0,0,0);
364   return 1;
365  }
366  switch(bsi->scope)
367  {
368   case LDAP_SCOPE_BASE:
369   case LDAP_SCOPE_SUBTREE:
370                 if ((rc=backsql_BindParamStr(sth,2,bsi->base_dn,BACKSQL_MAX_DN_LEN)) != SQL_SUCCESS)
371                 {
372          Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding base_dn parameter\n",0,0,0);
373                  backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
374          return 1;
375                 }
376                 break;
377   case LDAP_SCOPE_ONELEVEL:
378                 res=backsql_dn2id(bsi->bi,&base_id,bsi->dbh,bsi->base_dn);
379                 if (res==NULL)
380                 {
381                  Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): could not retrieve base_dn id - no such entry\n",0,0,0);
382                  bsi->status=LDAP_NO_SUCH_OBJECT;
383                  return 0;
384                 }
385                 if (backsql_BindParamID(sth,2,&base_id.id) != SQL_SUCCESS)
386                 {
387                  Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding base id parameter\n",0,0,0);
388                  free(base_id.dn);
389                  return 1;
390                 }               
391                 free(base_id.dn);
392                 break;
393  }
394  
395  if ((rc=SQLExecute(sth)) != SQL_SUCCESS && rc!= SQL_SUCCESS_WITH_INFO)
396   {
397    Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error executing query\n",0,0,0);
398    backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
399    SQLFreeStmt(sth,SQL_DROP);
400    return 1;
401   }
402
403  backsql_BindRowAsStrings(sth,&row);
404  while ((rc=SQLFetch(sth)) == SQL_SUCCESS || rc==SQL_SUCCESS_WITH_INFO)
405   {
406    /*
407    e=(Entry*)ch_calloc(1,sizeof(Entry)); 
408    for (i=1;i<row.ncols;i++)
409     {
410      if (row.is_null[i]>0)
411       {
412        backsql_entry_addattr(e,row.col_names[i],row.cols[i],row.col_prec[i]);
413 //       Debug(LDAP_DEBUG_TRACE,"prec=%d\n",(int)row.col_prec[i],0,0);
414       }
415     // else
416     //  Debug(LDAP_DEBUG_TRACE,"NULL value in this row for attribute '%s'\n",row.col_names[i],0,0);
417     }
418    */
419
420    c_id=(backsql_entryID*)ch_calloc(1,sizeof(backsql_entryID));
421    c_id->id=atoi(row.cols[0]);
422    c_id->keyval=atoi(row.cols[1]);
423    c_id->oc_id=bsi->oc->id;
424    c_id->dn=ch_strdup(row.cols[3]);
425    c_id->next=bsi->id_list;
426    bsi->id_list=c_id;
427    Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): added entry id=%d, keyval=%d dn='%s'\n",
428                 c_id->id,c_id->keyval,row.cols[3]);
429   }
430  backsql_FreeRow(&row);
431  SQLFreeStmt(sth,SQL_DROP);
432  Debug(LDAP_DEBUG_TRACE,"<==backsql_oc_get_candidates()\n",0,0,0);
433  return 1;
434 }
435
436 int backsql_search(BackendDB *be,Connection *conn,Operation *op,
437         const char *base, const char *nbase, int scope,int deref,int slimit,int tlimit,
438         Filter *filter, const char *filterstr,char **attrs,int attrsonly)
439 {
440  backsql_info *bi=(backsql_info*)be->be_private;
441  SQLHDBC dbh;
442  int sres;
443  int nentries;
444  Entry *entry,*res;
445  int manageDSAit = get_manageDSAit( op );
446  struct berval **v2refs = NULL;
447  time_t stoptime;
448  backsql_srch_info srch_info;
449  backsql_entryID *eid=NULL;
450
451  Debug(LDAP_DEBUG_TRACE,"==>backsql_search(): base='%s', filter='%s', scope=%d,",
452                      nbase,filterstr,scope);
453  Debug(LDAP_DEBUG_TRACE," deref=%d, attrsonly=%d, attributes to load: %s\n",
454          deref,attrsonly,attrs==NULL?"all":"custom list");
455  dbh=backsql_get_db_conn(be,conn);
456
457  if (!dbh)
458  {
459   Debug(LDAP_DEBUG_TRACE,"backsql_search(): could not get connection handle - exiting\n",0,0,0);
460   send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
461   return 1;
462  }
463  
464  if (tlimit == 0 && be_isroot(be,op->o_dn))
465   {
466    tlimit = -1; /* allow root to set no limit */
467   } 
468  else
469   {
470    tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
471                     be->be_timelimit : tlimit;
472    stoptime = op->o_time + tlimit;
473   }
474   
475  if (slimit == 0 && be_isroot(be,op->o_dn))
476   {
477    slimit = -1; /* allow root to set no limit */
478   }
479  else
480   {
481    slimit = (slimit > be->be_sizelimit || slimit < 1) ?
482                     be->be_sizelimit : slimit;
483   }
484
485  backsql_init_search(&srch_info,bi,(char*)nbase,scope,slimit,tlimit,stoptime,filter,dbh,
486                  be,conn,op,attrs);
487
488  //for each objectclass we try to construct query which gets IDs
489  //of entries matching LDAP query filter and scope (or at least candidates),
490  //and get the IDs
491  avl_apply(bi->oc_by_name,(AVL_APPLY)backsql_oc_get_candidates,&srch_info,0,AVL_INORDER);
492              
493  nentries=0;
494  //now we load candidate entries (only those attrubutes mentioned in attrs and filter),
495  //test it against full filter and then send to client
496  for(eid=srch_info.id_list;eid!=NULL;eid=eid->next)
497   {
498    /* check for abandon */
499    ldap_pvt_thread_mutex_lock(&op->o_abandonmutex);
500    if (op->o_abandon)
501     {
502      ldap_pvt_thread_mutex_unlock(&op->o_abandonmutex);
503      break;
504     }
505    ldap_pvt_thread_mutex_unlock(&op->o_abandonmutex);
506
507    /* check time limit */
508    if ( tlimit != -1 && slap_get_time() > stoptime)
509     {
510          send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED,
511                                 NULL, NULL, v2refs, NULL, nentries );
512      
513      break;
514     }
515      
516    Debug(LDAP_DEBUG_TRACE,"backsql_search(): loading data for entry id=%d, oc_id=%d, keyval=%d\n",
517                eid->id,eid->oc_id,eid->keyval);
518    
519    entry=(Entry *)ch_calloc(sizeof(Entry),1);
520    res=backsql_id2entry(&srch_info,entry,eid);
521    if (res==NULL)
522     {
523      Debug(LDAP_DEBUG_TRACE,"backsql_search(): error in backsql_id2entry() - skipping entry\n",0,0,0);
524      continue;
525     }
526
527    if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
528                         is_entry_referral( entry ) )
529     {
530      struct berval **refs = get_entry_referrals(be,conn,op,entry);
531
532      send_search_reference( be, conn, op, entry, refs, scope, NULL, &v2refs );
533      ber_bvecfree( refs );
534      continue;
535     }
536
537    if (test_filter(be,conn,op,entry,filter)==LDAP_COMPARE_TRUE)
538     {
539      if ((sres=send_search_entry(be,conn,op,entry,attrs,attrsonly,NULL))==-1)
540       {
541        Debug(LDAP_DEBUG_TRACE,"backsql_search(): connection lost\n",0,0,0);
542        break;
543       }
544      nentries+=!sres;                                   
545     }
546    entry_free(entry);
547   }
548
549  for(eid=srch_info.id_list;eid!=NULL;eid=backsql_free_entryID(eid));
550
551  charray_free(srch_info.attrs);
552
553  if (nentries>0)
554   send_search_result( conn, op,
555                 v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
556                 NULL, NULL, v2refs, NULL, nentries );
557  else
558   send_ldap_result(conn,op,LDAP_NO_SUCH_OBJECT,NULL,NULL,NULL,0);
559  
560  Debug(LDAP_DEBUG_TRACE,"<==backsql_search()\n",0,0,0);
561  return 0;
562 }
563
564 #endif /* SLAPD_SQL */