]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/util.c
Import ITS#4158 fixes from HEAD
[openldap] / servers / slapd / back-sql / util.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2005 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by Dmitry Kovalev for inclusion
18  * by OpenLDAP Software.
19  */
20
21 #include "portable.h"
22
23 #ifdef SLAPD_SQL
24
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include "ac/string.h"
28 #include "ac/ctype.h"
29 #include "ac/stdarg.h"
30
31 #include "slap.h"
32 #include "lber_pvt.h"
33 #include "ldap_pvt.h"
34 #include "proto-sql.h"
35
36 #define BACKSQL_MAX(a,b) ((a)>(b)?(a):(b))
37 #define BACKSQL_MIN(a,b) ((a)<(b)?(a):(b))
38
39 #define BACKSQL_STR_GROW 256
40
41 char backsql_def_oc_query[] = 
42         "SELECT id,name,keytbl,keycol,create_proc,delete_proc,expect_return "
43         "FROM ldap_oc_mappings";
44 char backsql_def_needs_select_oc_query[] = 
45         "SELECT id,name,keytbl,keycol,create_proc,create_keyval,delete_proc,"
46         "expect_return FROM ldap_oc_mappings";
47 char backsql_def_at_query[] = 
48         "SELECT name,sel_expr,from_tbls,join_where,add_proc,delete_proc,"
49         "param_order,expect_return,sel_expr_u FROM ldap_attr_mappings "
50         "WHERE oc_map_id=?";
51 char backsql_def_delentry_query[] = "DELETE FROM ldap_entries WHERE id=?";
52 char backsql_def_insentry_query[] = 
53         "INSERT INTO ldap_entries (dn,oc_map_id,parent,keyval) "
54         "VALUES (?,?,?,?)";
55 char backsql_def_delobjclasses_query[] = "DELETE FROM ldap_entry_objclasses "
56         "WHERE entry_id=?";
57 char backsql_def_delreferrals_query[] = "DELETE FROM ldap_referrals "
58         "WHERE entry_id=?";
59 char backsql_def_subtree_cond[] = "ldap_entries.dn LIKE CONCAT('%',?)";
60 char backsql_def_upper_subtree_cond[] = "(ldap_entries.dn) LIKE CONCAT('%',?)";
61 char backsql_id_query[] = "SELECT id,keyval,oc_map_id FROM ldap_entries WHERE ";
62 /* better ?||? or cast(?||? as varchar) */ 
63 char backsql_def_concat_func[] = "CONCAT(?,?)";
64
65 /* TimesTen */
66 char backsql_check_dn_ru_query[] = "SELECT dn_ru FROM ldap_entries";
67
68 struct berbuf *
69 backsql_strcat( struct berbuf *dest, ... )
70 {
71         va_list         strs;
72         ber_len_t       cdlen, cslen, grow;
73         char            *cstr;
74
75         assert( dest );
76         assert( dest->bb_val.bv_val == NULL 
77                         || dest->bb_val.bv_len == strlen( dest->bb_val.bv_val ) );
78  
79 #ifdef BACKSQL_TRACE
80         Debug( LDAP_DEBUG_TRACE, "==>backsql_strcat()\n", 0, 0, 0 );
81 #endif /* BACKSQL_TRACE */
82
83         va_start( strs, dest );
84         if ( dest->bb_val.bv_val == NULL || dest->bb_len == 0 ) {
85                 dest->bb_val.bv_val = (char *)ch_calloc( BACKSQL_STR_GROW, 
86                                 sizeof( char ) );
87                 dest->bb_val.bv_len = 0;
88                 dest->bb_len = BACKSQL_STR_GROW;
89         }
90         cdlen = dest->bb_val.bv_len;
91         while ( ( cstr = va_arg( strs, char * ) ) != NULL ) {
92                 cslen = strlen( cstr );
93                 grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen );
94                 if ( dest->bb_len - cdlen <= cslen ) {
95                         char    *tmp_dest;
96
97 #ifdef BACKSQL_TRACE
98                         Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
99                                 "buflen=%d, cdlen=%d, cslen=%d "
100                                 "-- reallocating dest\n",
101                                 dest->bb_len, cdlen + 1, cslen );
102 #endif /* BACKSQL_TRACE */
103
104                         tmp_dest = (char *)ch_realloc( dest->bb_val.bv_val,
105                                         ( dest->bb_len ) + grow * sizeof( char ) );
106                         if ( tmp_dest == NULL ) {
107                                 Debug( LDAP_DEBUG_ANY, "backsql_strcat(): "
108                                         "could not reallocate string buffer.\n",
109                                         0, 0, 0 );
110                                 return NULL;
111                         }
112                         dest->bb_val.bv_val = tmp_dest;
113                         dest->bb_len += grow;
114
115 #ifdef BACKSQL_TRACE
116                         Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
117                                 "new buflen=%d, dest=%p\n",
118                                 dest->bb_len, dest, 0 );
119 #endif /* BACKSQL_TRACE */
120                 }
121                 AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 );
122                 cdlen += cslen;
123         }
124         va_end( strs );
125
126 #ifdef BACKSQL_TRACE
127         Debug( LDAP_DEBUG_TRACE, "<==backsql_strcat() (dest=\"%s\")\n", 
128                         dest->bb_val.bv_val, 0, 0 );
129 #endif /* BACKSQL_TRACE */
130
131         dest->bb_val.bv_len = cdlen;
132
133         return dest;
134
135
136 struct berbuf *
137 backsql_strfcat( struct berbuf *dest, const char *fmt, ... )
138 {
139         va_list         strs;
140         ber_len_t       cdlen;
141
142         assert( dest );
143         assert( fmt );
144         assert( dest->bb_len == 0 || dest->bb_len > dest->bb_val.bv_len );
145         assert( dest->bb_val.bv_val == NULL 
146                         || dest->bb_val.bv_len == strlen( dest->bb_val.bv_val ) );
147  
148 #ifdef BACKSQL_TRACE
149         Debug( LDAP_DEBUG_TRACE, "==>backsql_strfcat()\n", 0, 0, 0 );
150 #endif /* BACKSQL_TRACE */
151
152         va_start( strs, fmt );
153         if ( dest->bb_val.bv_val == NULL || dest->bb_len == 0 ) {
154                 dest->bb_val.bv_val = (char *)ch_calloc( BACKSQL_STR_GROW, 
155                                 sizeof( char ) );
156                 dest->bb_val.bv_len = 0;
157                 dest->bb_len = BACKSQL_STR_GROW;
158         }
159
160         cdlen = dest->bb_val.bv_len;
161         for ( ; fmt[0]; fmt++ ) {
162                 ber_len_t       cslen, grow;
163                 char            *cstr, cc[ 2 ] = { '\0', '\0' };
164                 struct berval   *cbv;
165
166                 switch ( fmt[ 0 ] ) {
167
168                 /* berval */
169                 case 'b':
170                         cbv = va_arg( strs, struct berval * );
171                         cstr = cbv->bv_val;
172                         cslen = cbv->bv_len;
173                         break;
174
175                 /* length + string */
176                 case 'l':
177                         cslen = va_arg( strs, ber_len_t );
178                         cstr = va_arg( strs, char * );
179                         break;
180
181                 /* string */
182                 case 's':
183                         cstr = va_arg( strs, char * );
184                         cslen = strlen( cstr );
185                         break;
186
187                 /* char */
188                 case 'c':
189                         /* 
190                          * `char' is promoted to `int' when passed through `...'
191                          */
192                         cc[0] = va_arg( strs, int );
193                         cstr = cc;
194                         cslen = 1;
195                         break;
196
197                 default:
198                         assert( 0 );
199                 }
200
201                 grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen );
202                 if ( dest->bb_len - cdlen <= cslen ) {
203                         char    *tmp_dest;
204
205 #ifdef BACKSQL_TRACE
206                         Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): "
207                                 "buflen=%d, cdlen=%d, cslen=%d "
208                                 "-- reallocating dest\n",
209                                 dest->bb_len, cdlen + 1, cslen );
210 #endif /* BACKSQL_TRACE */
211
212                         tmp_dest = (char *)ch_realloc( dest->bb_val.bv_val,
213                                         ( dest->bb_len ) + grow * sizeof( char ) );
214                         if ( tmp_dest == NULL ) {
215                                 Debug( LDAP_DEBUG_ANY, "backsql_strfcat(): "
216                                         "could not reallocate string buffer.\n",
217                                         0, 0, 0 );
218                                 return NULL;
219                         }
220                         dest->bb_val.bv_val = tmp_dest;
221                         dest->bb_len += grow * sizeof( char );
222
223 #ifdef BACKSQL_TRACE
224                         Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): "
225                                 "new buflen=%d, dest=%p\n", dest->bb_len, dest, 0 );
226 #endif /* BACKSQL_TRACE */
227                 }
228
229                 assert( cstr );
230                 
231                 AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 );
232                 cdlen += cslen;
233         }
234
235         va_end( strs );
236
237 #ifdef BACKSQL_TRACE
238         Debug( LDAP_DEBUG_TRACE, "<==backsql_strfcat() (dest=\"%s\")\n", 
239                         dest->bb_val.bv_val, 0, 0 );
240 #endif /* BACKSQL_TRACE */
241
242         dest->bb_val.bv_len = cdlen;
243
244         return dest;
245
246
247 int
248 backsql_entry_addattr(
249         Entry           *e,
250         struct berval   *at_name,
251         struct berval   *at_val,
252         void            *memctx )
253 {
254         AttributeDescription    *ad;
255         int                     rc;
256         const char              *text;
257
258 #ifdef BACKSQL_TRACE
259         Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): "
260                 "at_name=\"%s\", at_val=\"%s\"\n", 
261                 at_name->bv_val, at_val->bv_val, 0 );
262 #endif /* BACKSQL_TRACE */
263
264         ad = NULL;
265         rc = slap_bv2ad( at_name, &ad, &text );
266         if ( rc != LDAP_SUCCESS ) {
267                 Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): "
268                         "failed to find AttributeDescription for \"%s\"\n",
269                         at_name->bv_val, 0, 0 );
270                 return 0;
271         }
272
273         rc = attr_merge_normalize_one( e, ad, at_val, memctx );
274
275         if ( rc != 0 ) {
276                 Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): "
277                         "failed to merge value \"%s\" for attribute \"%s\"\n",
278                         at_val->bv_val, at_name->bv_val, 0 );
279                 return 0;
280         }
281
282 #ifdef BACKSQL_TRACE
283         Debug( LDAP_DEBUG_TRACE, "<==backsql_query_addattr()\n", 0, 0, 0 );
284 #endif /* BACKSQL_TRACE */
285
286         return 1;
287 }
288
289 static char *
290 backsql_get_table_spec( char **p )
291 {
292         char            *s, *q;
293         struct berbuf   res = BB_NULL;
294
295         assert( p );
296         assert( *p );
297
298         s = *p;
299         while ( **p && **p != ',' ) {
300                 (*p)++;
301         }
302
303         if ( **p ) {
304                 *(*p)++ = '\0';
305         }
306         
307 #define BACKSQL_NEXT_WORD { \
308                 while ( *s && isspace( (unsigned char)*s ) ) s++; \
309                 if ( !*s ) return res.bb_val.bv_val; \
310                 q = s; \
311                 while ( *q && !isspace( (unsigned char)*q ) ) q++; \
312                 if ( *q ) *q++='\0'; \
313         }
314
315         BACKSQL_NEXT_WORD;
316         /* table name */
317         backsql_strcat( &res, s, NULL );
318         s = q;
319
320         BACKSQL_NEXT_WORD;
321         if ( strcasecmp( s, "AS" ) == 0 ) {
322                 s = q;
323                 BACKSQL_NEXT_WORD;
324         }
325
326         /* oracle doesn't understand "AS" :( and other RDBMSes don't need it */
327 #ifdef BACKSQL_ALIASING_QUOTE
328         backsql_strfcat( &res, "scsc", " " BACKSQL_ALIASING,
329                         BACKSQL_ALIASING_QUOTE, s, BACKSQL_ALIASING_QUOTE );
330 #else /* ! BACKSQL_ALIASING */
331         backsql_strcat( &res, " " BACKSQL_ALIASING, s, NULL );
332 #endif /* ! BACKSQL_ALIASING */
333
334         return res.bb_val.bv_val;
335 }
336
337 int
338 backsql_merge_from_clause( 
339         struct berbuf   *dest_from,
340         struct berval   *src_from )
341 {
342         char            *s, *p, *srcc, *pos, e;
343         struct berbuf   res = BB_NULL;
344
345 #ifdef BACKSQL_TRACE
346         Debug( LDAP_DEBUG_TRACE, "==>backsql_merge_from_clause(): "
347                 "dest_from=\"%s\",src_from=\"%s\"\n",
348                 dest_from ? dest_from->bb_val.bv_val : "<NULL>",
349                 src_from->bv_val, 0 );
350 #endif /* BACKSQL_TRACE */
351
352         srcc = ch_strdup( src_from->bv_val );
353         p = srcc;
354
355         if ( dest_from != NULL ) {
356                 res = *dest_from;
357         }
358         
359         while ( *p ) {
360                 s = backsql_get_table_spec( &p );
361
362 #ifdef BACKSQL_TRACE
363                 Debug( LDAP_DEBUG_TRACE, "backsql_merge_from_clause(): "
364                         "p=\"%s\" s=\"%s\"\n", p, s, 0 );
365 #endif /* BACKSQL_TRACE */
366
367                 if ( res.bb_val.bv_val == NULL ) {
368                         backsql_strcat( &res, s, NULL );
369
370                 } else {
371                         pos = strstr( res.bb_val.bv_val, s );
372                         if ( pos == NULL || ( ( e = pos[ strlen( s ) ] ) != '\0' && e != ',' ) ) {
373                                 backsql_strfcat( &res, "cs", ',', s );
374                         }
375                 }
376                 
377                 if ( s ) {
378                         ch_free( s );
379                 }
380         }
381
382 #ifdef BACKSQL_TRACE
383         Debug( LDAP_DEBUG_TRACE, "<==backsql_merge_from_clause()\n", 0, 0, 0 );
384 #endif /* BACKSQL_TRACE */
385
386         free( srcc );
387         *dest_from = res;
388
389         return 1;
390 }
391
392 /*
393  * splits a pattern in components separated by '?'
394  * (double ?? are turned into single ? and left in the string)
395  * expected contains the number of expected occurrences of '?'
396  * (a negative value means parse as many as possible)
397  */
398
399 int
400 backsql_split_pattern(
401         const char      *_pattern,
402         BerVarray       *split_pattern,
403         int             expected )
404 {
405         char            *pattern, *start, *end;
406         struct berval   bv;
407         int             rc = 0;
408
409 #define SPLIT_CHAR      '?'
410         
411         assert( _pattern );
412         assert( split_pattern );
413
414         pattern = ch_strdup( _pattern );
415
416         start = pattern;
417         end = strchr( start, SPLIT_CHAR );
418         for ( ; start; expected-- ) {
419                 char            *real_end = end;
420                 ber_len_t       real_len;
421                 
422                 if ( real_end == NULL ) {
423                         real_end = start + strlen( start );
424
425                 } else if ( real_end[ 1 ] == SPLIT_CHAR ) {
426                         expected++;
427                         AC_MEMCPY( real_end, real_end + 1, strlen( real_end ) );
428                         end = strchr( real_end + 1, SPLIT_CHAR );
429                         continue;
430                 }
431
432                 real_len = real_end - start;
433                 if ( real_len == 0 ) {
434                         ber_str2bv( "", 0, 1, &bv );
435                 } else {
436                         ber_str2bv( start, real_len, 1, &bv );
437                 }
438
439                 ber_bvarray_add( split_pattern, &bv );
440
441                 if ( expected == 0 ) {
442                         if ( end != NULL ) {
443                                 rc = -1;
444                                 goto done;
445                         }
446                         break;
447                 }
448
449                 if ( end != NULL ) {
450                         start = end + 1;
451                         end = strchr( start, SPLIT_CHAR );
452                 }
453         }
454
455 done:;
456
457         ch_free( pattern );
458
459         return rc;
460 }
461
462 int
463 backsql_prepare_pattern(
464         BerVarray       split_pattern,
465         BerVarray       values,
466         struct berval   *res )
467 {
468         int             i;
469         struct berbuf   bb = BB_NULL;
470
471         assert( res );
472
473         for ( i = 0; values[i].bv_val; i++ ) {
474                 if ( split_pattern[i].bv_val == NULL ) {
475                         ch_free( bb.bb_val.bv_val );
476                         return -1;
477                 }
478                 backsql_strfcat( &bb, "b", &split_pattern[ i ] );
479                 backsql_strfcat( &bb, "b", &values[ i ] );
480         }
481
482         if ( split_pattern[ i ].bv_val == NULL ) {
483                 ch_free( bb.bb_val.bv_val );
484                 return -1;
485         }
486
487         backsql_strfcat( &bb, "b", &split_pattern[ i ] );
488
489         *res = bb.bb_val;
490
491         return 0;
492 }
493
494 #endif /* SLAPD_SQL */
495