]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/schema-map.c
plug more leaks; few remain (but seem to be in ODBC)
[openldap] / servers / slapd / back-sql / schema-map.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  * Portions Copyright 2002 Pierangelo Masarati.
7  * Portions Copyright 2004 Mark Adamson.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by Dmitry Kovalev for inclusion
20  * by OpenLDAP Software.  Additional significant contributors include
21  * Pierangelo Masarati and Mark Adamson.
22  */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include "ac/string.h"
29
30 #include "slap.h"
31 #include "proto-sql.h"
32
33 #define BACKSQL_DUPLICATE       (-1)
34
35 /* NOTE: by default, cannot just compare pointers because
36  * objectClass/attributeType order would be machine-dependent
37  * (and tests would fail!); however, if you don't want to run
38  * tests, or see attributeTypes written in the same order
39  * they are defined, define */
40 /* #undef BACKSQL_USE_PTR_CMP */
41
42 /*
43  * Uses the pointer to the ObjectClass structure
44  */
45 static int
46 backsql_cmp_oc( const void *v_m1, const void *v_m2 )
47 {
48         const backsql_oc_map_rec        *m1 = v_m1,
49                                         *m2 = v_m2;
50
51 #ifdef BACKSQL_USE_PTR_CMP
52         return SLAP_PTRCMP( m1->bom_oc, m2->bom_oc );
53 #else /* ! BACKSQL_USE_PTR_CMP */
54         return ber_bvcmp( &m1->bom_oc->soc_cname, &m2->bom_oc->soc_cname );
55 #endif /* ! BACKSQL_USE_PTR_CMP */
56 }
57
58 static int
59 backsql_cmp_oc_id( const void *v_m1, const void *v_m2 )
60 {
61         const backsql_oc_map_rec        *m1 = v_m1,
62                                         *m2 = v_m2;
63
64         return ( m1->bom_id < m2->bom_id ? -1 : ( m1->bom_id > m2->bom_id ? 1 : 0 ) );
65 }
66
67 /*
68  * Uses the pointer to the AttributeDescription structure
69  */
70 static int
71 backsql_cmp_attr( const void *v_m1, const void *v_m2 )
72 {
73         const backsql_at_map_rec        *m1 = v_m1,
74                                         *m2 = v_m2;
75
76 #ifdef BACKSQL_USE_PTR_CMP
77         return SLAP_PTRCMP( m1->bam_ad, m2->bam_ad );
78 #else /* ! BACKSQL_USE_PTR_CMP */
79         return ber_bvcmp( &m1->bam_ad->ad_cname, &m2->bam_ad->ad_cname );
80 #endif /* ! BACKSQL_USE_PTR_CMP */
81 }
82
83 int
84 backsql_dup_attr( void *v_m1, void *v_m2 )
85 {
86         backsql_at_map_rec              *m1 = v_m1,
87                                         *m2 = v_m2;
88
89         assert( m1->bam_ad == m2->bam_ad );
90
91         /* duplicate definitions of attributeTypes are appended;
92          * this allows to define multiple rules for the same 
93          * attributeType.  Use with care! */
94         for ( ; m1->bam_next ; m1 = m1->bam_next );
95         m1->bam_next = m2;
96         m2->bam_next = NULL;
97
98         return BACKSQL_DUPLICATE;
99 }
100
101 static int
102 backsql_make_attr_query( 
103         backsql_info            *bi,
104         backsql_oc_map_rec      *oc_map,
105         backsql_at_map_rec      *at_map )
106 {
107         struct berbuf   bb = BB_NULL;
108
109         backsql_strfcat( &bb, "lblbbbblblbcbl", 
110                         (ber_len_t)STRLENOF( "SELECT " ), "SELECT ", 
111                         &at_map->bam_sel_expr, 
112                         (ber_len_t)STRLENOF( " " ), " ",
113                         &bi->sql_aliasing,
114                         &bi->sql_aliasing_quote, 
115                         &at_map->bam_ad->ad_cname,
116                         &bi->sql_aliasing_quote,
117                         (ber_len_t)STRLENOF( " FROM " ), " FROM ", 
118                         &at_map->bam_from_tbls, 
119                         (ber_len_t)STRLENOF( " WHERE " ), " WHERE ", 
120                         &oc_map->bom_keytbl,
121                         '.', 
122                         &oc_map->bom_keycol,
123                         (ber_len_t)STRLENOF( "=?" ), "=?" );
124
125         if ( !BER_BVISNULL( &at_map->bam_join_where ) ) {
126                 backsql_strfcat( &bb, "lb",
127                                 (ber_len_t)STRLENOF( " AND " ), " AND ", 
128                                 &at_map->bam_join_where );
129         }
130
131         backsql_strfcat( &bb, "lbbb", 
132                         (ber_len_t)STRLENOF( " ORDER BY " ), " ORDER BY ",
133                         &bi->sql_aliasing_quote,
134                         &at_map->bam_ad->ad_cname,
135                         &bi->sql_aliasing_quote );
136
137         at_map->bam_query = bb.bb_val.bv_val;
138
139 #ifdef BACKSQL_COUNTQUERY
140         /* Query to count how many rows will be returned. */
141         BER_BVZERO( &bb.bb_val );
142         bb.bb_len = 0;
143         backsql_strfcat( &bb, "lblbcbl", 
144                         (ber_len_t)STRLENOF( "SELECT COUNT(*) FROM " ),
145                                 "SELECT COUNT(*) FROM ", 
146                         &at_map->bam_from_tbls, 
147                         (ber_len_t)STRLENOF( " WHERE " ), " WHERE ", 
148                         &oc_map->bom_keytbl,
149                         '.', 
150                         &oc_map->bom_keycol,
151                         (ber_len_t)STRLENOF( "=?" ), "=?" );
152
153         if ( !BER_BVISNULL( &at_map->bam_join_where ) ) {
154                 backsql_strfcat( &bb, "lb",
155                                 (ber_len_t)STRLENOF( " AND " ), " AND ", 
156                                 &at_map->bam_join_where );
157         }
158
159         at_map->bam_countquery = bb.bb_val.bv_val;
160 #endif /* BACKSQL_COUNTQUERY */
161
162         return 0;
163 }
164
165 static int
166 backsql_add_sysmaps( backsql_info *bi, backsql_oc_map_rec *oc_map )
167 {
168         backsql_at_map_rec      *at_map;
169         char                    s[] = "+9223372036854775807L";
170         struct berval           sbv;
171         struct berbuf           bb;
172         
173         sbv.bv_val = s;
174         sbv.bv_len = snprintf( s, sizeof( s ), "%ld", oc_map->bom_id );
175
176         /* extra objectClasses */
177         at_map = (backsql_at_map_rec *)ch_calloc(1, 
178                         sizeof( backsql_at_map_rec ) );
179         at_map->bam_ad = slap_schema.si_ad_objectClass;
180         ber_str2bv( "ldap_entry_objclasses.oc_name", 0, 1,
181                         &at_map->bam_sel_expr );
182         ber_str2bv( "ldap_entry_objclasses,ldap_entries", 0, 1, 
183                         &at_map->bam_from_tbls );
184         
185         bb.bb_len = at_map->bam_from_tbls.bv_len + 1;
186         bb.bb_val = at_map->bam_from_tbls;
187         backsql_merge_from_clause( bi, &bb, &oc_map->bom_keytbl );
188         at_map->bam_from_tbls = bb.bb_val;
189
190         BER_BVZERO( &bb.bb_val );
191         bb.bb_len = 0;
192         backsql_strfcat( &bb, "lbcblb",
193                         (ber_len_t)STRLENOF( "ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entries.keyval=" ),
194                                 "ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entries.keyval=",
195                         &oc_map->bom_keytbl, 
196                         '.', 
197                         &oc_map->bom_keycol,
198                         (ber_len_t)STRLENOF( " and ldap_entries.oc_map_id=" ), 
199                                 " and ldap_entries.oc_map_id=", 
200                         &sbv );
201         at_map->bam_join_where = bb.bb_val;
202
203         at_map->bam_oc = oc_map->bom_oc;
204
205         at_map->bam_add_proc = NULL;
206         {
207                 char    tmp[] =
208                         "INSERT INTO ldap_entry_objclasses "
209                         "(entry_id,oc_name) VALUES "
210                         "((SELECT id FROM ldap_entries "
211                         "WHERE oc_map_id="
212                         "18446744073709551615UL "       /* 64 bit ULONG */
213                         "AND keyval=?),?)";
214                 snprintf( tmp, sizeof(tmp), 
215                         "INSERT INTO ldap_entry_objclasses "
216                         "(entry_id,oc_name) VALUES "
217                         "((SELECT id FROM ldap_entries "
218                         "WHERE oc_map_id=%lu "
219                         "AND keyval=?),?)", oc_map->bom_id );
220                 at_map->bam_add_proc = ch_strdup( tmp );
221         }
222
223         at_map->bam_delete_proc = NULL;
224         {
225                 char    tmp[] =
226                         "DELETE FROM ldap_entry_objclasses "
227                         "WHERE entry_id=(SELECT id FROM ldap_entries "
228                         "WHERE oc_map_id="
229                         "18446744073709551615UL "       /* 64 bit ULONG */
230                         "AND keyval=?) AND oc_name=?";
231                 snprintf( tmp, sizeof(tmp), 
232                         "DELETE FROM ldap_entry_objclasses "
233                         "WHERE entry_id=(SELECT id FROM ldap_entries "
234                         "WHERE oc_map_id=%lu"
235                         "AND keyval=?) AND oc_name=?",
236                         oc_map->bom_id );
237                 at_map->bam_delete_proc = ch_strdup( tmp );
238         }
239
240         at_map->bam_param_order = 0;
241         at_map->bam_expect_return = 0;
242         at_map->bam_next = NULL;
243
244         backsql_make_attr_query( bi, oc_map, at_map );
245         if ( avl_insert( &oc_map->bom_attrs, at_map, backsql_cmp_attr, backsql_dup_attr ) == BACKSQL_DUPLICATE ) {
246                 Debug( LDAP_DEBUG_TRACE, "backsql_add_sysmaps(): "
247                                 "duplicate attribute \"%s\" in objectClass \"%s\" map\n",
248                                 at_map->bam_ad->ad_cname.bv_val,
249                                 oc_map->bom_oc->soc_cname.bv_val, 0 );
250         }
251
252         /* FIXME: we need to correct the objectClass join_where 
253          * after the attribute query is built */
254         ch_free( at_map->bam_join_where.bv_val );
255         BER_BVZERO( &bb.bb_val );
256         bb.bb_len = 0;
257         backsql_strfcat( &bb, "lbcblb",
258                         (ber_len_t)STRLENOF( /* "ldap_entries.id=ldap_entry_objclasses.entry_id AND " */ "ldap_entries.keyval=" ),
259                                 /* "ldap_entries.id=ldap_entry_objclasses.entry_id AND " */ "ldap_entries.keyval=",
260                         &oc_map->bom_keytbl, 
261                         '.', 
262                         &oc_map->bom_keycol,
263                         (ber_len_t)STRLENOF( " AND ldap_entries.oc_map_id=" ), 
264                                 " AND ldap_entries.oc_map_id=", 
265                         &sbv );
266         at_map->bam_join_where = bb.bb_val;
267
268         return 1;
269 }
270
271 struct backsql_attr_schema_info {
272         backsql_info    *bas_bi;
273         SQLHDBC         bas_dbh;
274         SQLHSTMT        bas_sth;
275         unsigned long   *bas_oc_id;
276         int             bas_rc;
277 };
278
279 static int
280 backsql_oc_get_attr_mapping( void *v_oc, void *v_bas )
281 {
282         RETCODE                         rc;
283         BACKSQL_ROW_NTS                 at_row;
284         backsql_oc_map_rec              *oc_map = (backsql_oc_map_rec *)v_oc;
285         backsql_at_map_rec              *at_map;
286         struct backsql_attr_schema_info *bas = (struct backsql_attr_schema_info *)v_bas;
287
288         /* bas->bas_oc_id has been bound to bas->bas_sth */
289         *bas->bas_oc_id = oc_map->bom_id;
290
291         Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
292                 "executing at_query\n"
293                 "    \"%s\"\n"
294                 "    for objectClass \"%s\"\n"
295                 "    with param oc_id=\"%lu\"\n",
296                 bas->bas_bi->sql_at_query,
297                 BACKSQL_OC_NAME( oc_map ),
298                 *bas->bas_oc_id );
299
300         rc = SQLExecute( bas->bas_sth );
301         if ( rc != SQL_SUCCESS ) {
302                 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
303                         "error executing at_query\n"
304                         "    \"%s\"\n"
305                         "    for objectClass \"%s\"\n"
306                         "    with param oc_id=\"%lu\"\n",
307                         bas->bas_bi->sql_at_query,
308                         BACKSQL_OC_NAME( oc_map ),
309                         *bas->bas_oc_id );
310                 backsql_PrintErrors( bas->bas_bi->sql_db_env,
311                                 bas->bas_dbh, bas->bas_sth, rc );
312                 bas->bas_rc = LDAP_OTHER;
313                 return BACKSQL_AVL_STOP;
314         }
315
316         backsql_BindRowAsStrings( bas->bas_sth, &at_row );
317         for ( ; rc = SQLFetch( bas->bas_sth ), BACKSQL_SUCCESS( rc ); ) {
318                 const char      *text = NULL;
319                 char            *next = NULL;
320                 struct berval   bv;
321                 struct berbuf   bb = BB_NULL;
322
323                 Debug( LDAP_DEBUG_TRACE, 
324                         "attributeType:\n"
325                         "\tname=\"%s\"\n"
326                         "\tsel_expr=\"%s\"\n"
327                         "\tfrom=\"%s\"\n",
328                         at_row.cols[ 0 ], at_row.cols[ 1 ],
329                         at_row.cols[ 2 ] );
330                 Debug( LDAP_DEBUG_TRACE, 
331                         "\tjoin_where=\"%s\"\n"
332                         "\tadd_proc=\"%s\"\n"
333                         "\tdelete_proc=\"%s\"\n",
334                         at_row.cols[ 3 ], at_row.cols[ 4 ],
335                         at_row.cols[ 5 ]);
336                 /* TimesTen */
337                 Debug( LDAP_DEBUG_TRACE, "\tsel_expr_u=\"%s\"\n",
338                                 at_row.cols[ 8 ], 0, 0 );
339                 at_map = (backsql_at_map_rec *)ch_calloc( 1,
340                                 sizeof( backsql_at_map_rec ) );
341                 rc = slap_str2ad( at_row.cols[ 0 ], 
342                                 &at_map->bam_ad, &text );
343                 if ( rc != LDAP_SUCCESS ) {
344                         Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
345                                 "attribute \"%s\" for objectClass \"%s\" "
346                                 "is not defined in schema: %s\n", 
347                                 at_row.cols[ 0 ],
348                                 BACKSQL_OC_NAME( oc_map ), text );
349                         bas->bas_rc = LDAP_CONSTRAINT_VIOLATION;
350                         return BACKSQL_AVL_STOP;
351                 }
352
353                 ber_str2bv( at_row.cols[ 1 ], 0, 1, &at_map->bam_sel_expr );
354                 if ( at_row.value_len[ 8 ] < 0 ) {
355                         BER_BVZERO( &at_map->bam_sel_expr_u );
356
357                 } else {
358                         ber_str2bv( at_row.cols[ 8 ], 0, 1, 
359                                         &at_map->bam_sel_expr_u );
360                 }
361
362                 ber_str2bv( at_row.cols[ 2 ], 0, 0, &bv );
363                 backsql_merge_from_clause( bas->bas_bi, &bb, &bv );
364                 at_map->bam_from_tbls = bb.bb_val;
365                 if ( at_row.value_len[ 3 ] < 0 ) {
366                         BER_BVZERO( &at_map->bam_join_where );
367
368                 } else {
369                         ber_str2bv( at_row.cols[ 3 ], 0, 1, 
370                                         &at_map->bam_join_where );
371                 }
372                 at_map->bam_add_proc = NULL;
373                 if ( at_row.value_len[ 4 ] > 0 ) {
374                         at_map->bam_add_proc = ch_strdup( at_row.cols[4] );
375                 }
376                 at_map->bam_delete_proc = NULL;
377                 if ( at_row.value_len[ 5 ] > 0 ) {
378                         at_map->bam_delete_proc = ch_strdup( at_row.cols[ 5 ] );
379                 }
380                 at_map->bam_param_order = strtol( at_row.cols[ 6 ], 
381                                 &next, 0 );
382                 if ( next == at_row.cols[ 6 ] || next[0] != '\0' ) {
383                         /* error */
384                 }
385                 at_map->bam_expect_return = strtol( at_row.cols[ 7 ],
386                                 &next, 0 );
387                 if ( next == at_row.cols[ 7 ] || next[0] != '\0' ) {
388                         /* error */
389                 }
390                 backsql_make_attr_query( bas->bas_bi, oc_map, at_map );
391                 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
392                         "preconstructed query \"%s\"\n",
393                         at_map->bam_query, 0, 0 );
394                 at_map->bam_next = NULL;
395                 if ( avl_insert( &oc_map->bom_attrs, at_map, backsql_cmp_attr, backsql_dup_attr ) == BACKSQL_DUPLICATE ) {
396                         Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
397                                         "duplicate attribute \"%s\" "
398                                         "in objectClass \"%s\" map\n",
399                                         at_map->bam_ad->ad_cname.bv_val,
400                                         oc_map->bom_oc->soc_cname.bv_val, 0 );
401                 }
402
403                 if ( !BER_BVISNULL( &bas->bas_bi->sql_upper_func ) &&
404                                 BER_BVISNULL( &at_map->bam_sel_expr_u ) )
405                 {
406                         struct berbuf   bb = BB_NULL;
407
408                         backsql_strfcat( &bb, "bcbc",
409                                         &bas->bas_bi->sql_upper_func,
410                                         '(' /* ) */ ,
411                                         &at_map->bam_sel_expr,
412                                         /* ( */ ')' );
413                         at_map->bam_sel_expr_u = bb.bb_val;
414                 }
415         }
416         backsql_FreeRow( &at_row );
417         SQLFreeStmt( bas->bas_sth, SQL_CLOSE );
418
419         Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(\"%s\"): "
420                 "autoadding 'objectClass' and 'ref' mappings\n",
421                 BACKSQL_OC_NAME( oc_map ), 0, 0 );
422
423         (void)backsql_add_sysmaps( bas->bas_bi, oc_map );
424
425         return BACKSQL_AVL_CONTINUE;
426 }
427
428
429 int
430 backsql_load_schema_map( backsql_info *bi, SQLHDBC dbh )
431 {
432         SQLHSTMT                        sth = SQL_NULL_HSTMT;
433         RETCODE                         rc;
434         BACKSQL_ROW_NTS                 oc_row;
435         unsigned long                   oc_id;
436         backsql_oc_map_rec              *oc_map;
437         struct backsql_attr_schema_info bas;
438
439         Debug( LDAP_DEBUG_TRACE, "==>backsql_load_schema_map()\n", 0, 0, 0 );
440
441         /* 
442          * TimesTen : See if the ldap_entries.dn_ru field exists in the schema
443          */
444         if ( !BACKSQL_DONTCHECK_LDAPINFO_DN_RU( bi ) ) {
445                 rc = backsql_Prepare( dbh, &sth, 
446                                 backsql_check_dn_ru_query, 0 );
447                 if ( rc == SQL_SUCCESS ) {
448                         /* Yes, the field exists */
449                         bi->sql_flags |= BSQLF_HAS_LDAPINFO_DN_RU;
450                         Debug( LDAP_DEBUG_TRACE, "ldapinfo.dn_ru field exists "
451                                 "in the schema\n", 0, 0, 0 );
452                 } else {
453                         /* No such field exists */
454                         bi->sql_flags &= ~BSQLF_HAS_LDAPINFO_DN_RU;
455                 }
456
457                 SQLFreeStmt( sth, SQL_DROP );
458         }
459
460         Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): oc_query \"%s\"\n", 
461                         bi->sql_oc_query, 0, 0 );
462
463         rc = backsql_Prepare( dbh, &sth, bi->sql_oc_query, 0 );
464         if ( rc != SQL_SUCCESS ) {
465                 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
466                         "error preparing oc_query: \"%s\"\n", 
467                         bi->sql_oc_query, 0, 0 );
468                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
469                 return LDAP_OTHER;
470         }
471
472         rc = SQLExecute( sth );
473         if ( rc != SQL_SUCCESS ) {
474                 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
475                         "error executing oc_query: \n", 0, 0, 0 );
476                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
477                 return LDAP_OTHER;
478         }
479
480         backsql_BindRowAsStrings( sth, &oc_row );
481         rc = SQLFetch( sth );
482         for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
483                 int     colnum;
484
485                 oc_map = (backsql_oc_map_rec *)ch_calloc( 1,
486                                 sizeof( backsql_oc_map_rec ) );
487
488                 oc_map->bom_id = strtol( oc_row.cols[ 0 ], NULL, 0 );
489
490                 oc_map->bom_oc = oc_find( oc_row.cols[ 1 ] );
491                 if ( oc_map->bom_oc == NULL ) {
492                         Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
493                                 "objectClass \"%s\" is not defined in schema\n", 
494                                 oc_row.cols[ 1 ], 0, 0 );
495                         return LDAP_OTHER;      /* undefined objectClass ? */
496                 }
497                 
498                 ber_str2bv( oc_row.cols[ 2 ], 0, 1, &oc_map->bom_keytbl );
499                 ber_str2bv( oc_row.cols[ 3 ], 0, 1, &oc_map->bom_keycol );
500                 oc_map->bom_create_proc = ( oc_row.value_len[ 4 ] < 0 ) ? NULL 
501                         : ch_strdup( oc_row.cols[ 4 ] );
502
503                 colnum = 5;
504                 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
505                         colnum = 6;
506                         oc_map->bom_create_keyval = ( oc_row.value_len[ 5 ] < 0 ) 
507                                 ? NULL : ch_strdup( oc_row.cols[ 5 ] );
508                 }
509                 oc_map->bom_delete_proc = ( oc_row.value_len[ colnum ] < 0 ) ? NULL 
510                         : ch_strdup( oc_row.cols[ colnum ] );
511                 oc_map->bom_expect_return = strtol( oc_row.cols[ colnum + 1 ], 
512                                 NULL, 0 );
513
514                 colnum += 2;
515                 if ( ( oc_row.ncols > colnum ) &&
516                                 ( oc_row.value_len[ colnum ] > 0 ) )
517                 {
518                         const char      *text;
519
520                         oc_map->bom_create_hint = NULL;
521                         rc = slap_str2ad( oc_row.cols[ colnum ],
522                                         &oc_map->bom_create_hint, &text );
523                         if ( rc != SQL_SUCCESS ) {
524                                 Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
525                                                 "error matching "
526                                                 "AttributeDescription %s "
527                                                 "in create_hint: %s (%d)\n",
528                                                 oc_row.cols[ colnum ],
529                                                 text, rc );
530                                 backsql_PrintErrors( bi->sql_db_env, dbh,
531                                                 sth, rc );
532                                 return LDAP_OTHER;
533                         }
534                 }
535
536                 /*
537                  * FIXME: first attempt to check for offending
538                  * instructions in {create|delete}_proc
539                  */
540
541                 oc_map->bom_attrs = NULL;
542                 if ( avl_insert( &bi->sql_oc_by_oc, oc_map, backsql_cmp_oc, avl_dup_error ) == -1 ) {
543                         Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
544                                         "duplicate objectClass \"%s\" in objectClass map\n",
545                                         oc_map->bom_oc->soc_cname.bv_val, 0, 0 );
546                         return LDAP_OTHER;
547                 }
548                 if ( avl_insert( &bi->sql_oc_by_id, oc_map, backsql_cmp_oc_id, avl_dup_error ) == -1 ) {
549                         Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
550                                         "duplicate objectClass \"%s\" in objectClass by ID map\n",
551                                         oc_map->bom_oc->soc_cname.bv_val, 0, 0 );
552                         return LDAP_OTHER;
553                 }
554                 oc_id = oc_map->bom_id;
555                 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
556                         "objectClass \"%s\":\n    keytbl=\"%s\" keycol=\"%s\"\n",
557                         BACKSQL_OC_NAME( oc_map ),
558                         oc_map->bom_keytbl.bv_val, oc_map->bom_keycol.bv_val );
559                 if ( oc_map->bom_create_proc ) {
560                         Debug( LDAP_DEBUG_TRACE, "    create_proc=\"%s\"\n",
561                                 oc_map->bom_create_proc, 0, 0 );
562                 }
563                 if ( oc_map->bom_create_keyval ) {
564                         Debug( LDAP_DEBUG_TRACE, "    create_keyval=\"%s\"\n",
565                                 oc_map->bom_create_keyval, 0, 0 );
566                 }
567                 if ( oc_map->bom_create_hint ) {
568                         Debug( LDAP_DEBUG_TRACE, "    create_hint=\"%s\"\n", 
569                                 oc_map->bom_create_hint->ad_cname.bv_val,
570                                 0, 0 );
571                 }
572                 if ( oc_map->bom_delete_proc ) {
573                         Debug( LDAP_DEBUG_TRACE, "    delete_proc=\"%s\"\n", 
574                                 oc_map->bom_delete_proc, 0, 0 );
575                 }
576                 Debug( LDAP_DEBUG_TRACE, "    expect_return: "
577                         "add=%d, del=%d; attributes:\n",
578                         BACKSQL_IS_ADD( oc_map->bom_expect_return ), 
579                         BACKSQL_IS_DEL( oc_map->bom_expect_return ), 0 );
580         }
581
582         backsql_FreeRow( &oc_row );
583         SQLFreeStmt( sth, SQL_DROP );
584
585         /* prepare for attribute fetching */
586         Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): at_query \"%s\"\n", 
587                         bi->sql_at_query, 0, 0 );
588
589         rc = backsql_Prepare( dbh, &sth, bi->sql_at_query, 0 );
590         if ( rc != SQL_SUCCESS ) {
591                 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
592                         "error preparing at_query: \"%s\"\n", 
593                         bi->sql_at_query, 0, 0 );
594                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
595                 return LDAP_OTHER;
596         }
597
598         rc = backsql_BindParamInt( sth, 1, SQL_PARAM_INPUT, &oc_id );
599         if ( rc != SQL_SUCCESS ) {
600                 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
601                         "error binding param \"oc_id\" for at_query\n", 0, 0, 0 );
602                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
603                 SQLFreeStmt( sth, SQL_DROP );
604                 return LDAP_OTHER;
605         }
606
607         bas.bas_bi = bi;
608         bas.bas_dbh = dbh;
609         bas.bas_sth = sth;
610         bas.bas_oc_id = &oc_id;
611         bas.bas_rc = LDAP_SUCCESS;
612
613         (void)avl_apply( bi->sql_oc_by_oc, backsql_oc_get_attr_mapping,
614                         &bas, BACKSQL_AVL_STOP, AVL_INORDER );
615
616         SQLFreeStmt( sth, SQL_DROP );
617
618         bi->sql_flags |= BSQLF_SCHEMA_LOADED;
619
620         Debug( LDAP_DEBUG_TRACE, "<==backsql_load_schema_map()\n", 0, 0, 0 );
621
622         return bas.bas_rc;
623 }
624
625 backsql_oc_map_rec *
626 backsql_oc2oc( backsql_info *bi, ObjectClass *oc )
627 {
628         backsql_oc_map_rec      tmp, *res;
629
630 #ifdef BACKSQL_TRACE
631         Debug( LDAP_DEBUG_TRACE, "==>backsql_oc2oc(): "
632                 "searching for objectclass with name=\"%s\"\n",
633                 oc->soc_cname.bv_val, 0, 0 );
634 #endif /* BACKSQL_TRACE */
635
636         tmp.bom_oc = oc;
637         res = (backsql_oc_map_rec *)avl_find( bi->sql_oc_by_oc, &tmp, backsql_cmp_oc );
638 #ifdef BACKSQL_TRACE
639         if ( res != NULL ) {
640                 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
641                         "found name=\"%s\", id=%d\n", 
642                         BACKSQL_OC_NAME( res ), res->bom_id, 0 );
643         } else {
644                 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
645                         "not found\n", 0, 0, 0 );
646         }
647 #endif /* BACKSQL_TRACE */
648  
649         return res;
650 }
651
652 backsql_oc_map_rec *
653 backsql_name2oc( backsql_info *bi, struct berval *oc_name )
654 {
655         backsql_oc_map_rec      tmp, *res;
656
657 #ifdef BACKSQL_TRACE
658         Debug( LDAP_DEBUG_TRACE, "==>oc_with_name(): "
659                 "searching for objectclass with name=\"%s\"\n",
660                 oc_name->bv_val, 0, 0 );
661 #endif /* BACKSQL_TRACE */
662
663         tmp.bom_oc = oc_bvfind( oc_name );
664         if ( tmp.bom_oc == NULL ) {
665                 return NULL;
666         }
667
668         res = (backsql_oc_map_rec *)avl_find( bi->sql_oc_by_oc, &tmp, backsql_cmp_oc );
669 #ifdef BACKSQL_TRACE
670         if ( res != NULL ) {
671                 Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
672                         "found name=\"%s\", id=%d\n", 
673                         BACKSQL_OC_NAME( res ), res->bom_id, 0 );
674         } else {
675                 Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
676                         "not found\n", 0, 0, 0 );
677         }
678 #endif /* BACKSQL_TRACE */
679  
680         return res;
681 }
682
683 backsql_oc_map_rec *
684 backsql_id2oc( backsql_info *bi, unsigned long id )
685 {
686         backsql_oc_map_rec      tmp, *res;
687  
688 #ifdef BACKSQL_TRACE
689         Debug( LDAP_DEBUG_TRACE, "==>oc_with_id(): "
690                 "searching for objectclass with id='%d'\n", id, 0, 0 );
691 #endif /* BACKSQL_TRACE */
692
693         tmp.bom_id = id;
694         res = (backsql_oc_map_rec *)avl_find( bi->sql_oc_by_id, &tmp,
695                         backsql_cmp_oc_id );
696
697 #ifdef BACKSQL_TRACE
698         if ( res != NULL ) {
699                 Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
700                         "found name=\"%s\", id=%d\n",
701                         BACKSQL_OC_NAME( res ), res->bom_id, 0 );
702         } else {
703                 Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
704                         "not found\n", 0, 0, 0 );
705         }
706 #endif /* BACKSQL_TRACE */
707         
708         return res;
709 }
710
711 backsql_at_map_rec *
712 backsql_ad2at( backsql_oc_map_rec* objclass, AttributeDescription *ad )
713 {
714         backsql_at_map_rec      tmp, *res;
715  
716 #ifdef BACKSQL_TRACE
717         Debug( LDAP_DEBUG_TRACE, "==>backsql_ad2at(): "
718                 "searching for attribute \"%s\" for objectclass \"%s\"\n",
719                 ad->ad_cname.bv_val, BACKSQL_OC_NAME( objclass ), 0 );
720 #endif /* BACKSQL_TRACE */
721
722         tmp.bam_ad = ad;
723         res = (backsql_at_map_rec *)avl_find( objclass->bom_attrs, &tmp,
724                         backsql_cmp_attr );
725
726 #ifdef BACKSQL_TRACE
727         if ( res != NULL ) {
728                 Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
729                         "found name=\"%s\", sel_expr=\"%s\"\n",
730                         res->bam_ad->ad_cname.bv_val,
731                         res->bam_sel_expr.bv_val, 0 );
732         } else {
733                 Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
734                         "not found\n", 0, 0, 0 );
735         }
736 #endif /* BACKSQL_TRACE */
737
738         return res;
739 }
740
741 /* attributeType inheritance */
742 struct supad2at_t {
743         backsql_at_map_rec      **ret;
744         AttributeDescription    *ad;
745         unsigned                n;
746 };
747
748 #define SUPAD2AT_STOP   (-1)
749
750 static int
751 supad2at_f( void *v_at, void *v_arg )
752 {
753         backsql_at_map_rec      *at = (backsql_at_map_rec *)v_at;
754         struct supad2at_t       *va = (struct supad2at_t *)v_arg;
755
756         if ( is_at_subtype( at->bam_ad->ad_type, va->ad->ad_type ) ) {
757                 backsql_at_map_rec      **ret = NULL;
758                 unsigned                i;
759
760                 /* if already listed, holler! (should never happen) */
761                 if ( va->ret ) {
762                         for ( i = 0; i < va->n; i++ ) {
763                                 if ( va->ret[ i ]->bam_ad == at->bam_ad ) {
764                                         break;
765                                 }
766                         }
767
768                         if ( i < va->n ) {
769                                 return 0;
770                         }
771                 }
772
773                 ret = ch_realloc( va->ret,
774                                 sizeof( backsql_at_map_rec * ) * ( va->n + 2 ) );
775                 if ( ret == NULL ) {
776                         ch_free( va->ret );
777                         va->ret = NULL;
778                         va->n = 0;
779                         return SUPAD2AT_STOP;
780                 }
781
782                 ret[ va->n ] = at;
783                 va->n++;
784                 ret[ va->n ] = NULL;
785                 va->ret = ret;
786         }
787
788         return 0;
789 }
790
791 /*
792  * stores in *pret a NULL terminated array of pointers
793  * to backsql_at_map_rec whose attributeType is supad->ad_type 
794  * or derived from it
795  */
796 int
797 backsql_supad2at( backsql_oc_map_rec *objclass, AttributeDescription *supad,
798                 backsql_at_map_rec ***pret )
799 {
800         struct supad2at_t       va = { 0 };
801         int                     rc;
802
803         assert( objclass != NULL );
804         assert( supad != NULL );
805         assert( pret != NULL );
806
807         *pret = NULL;
808
809         va.ad = supad;
810
811         rc = avl_apply( objclass->bom_attrs, supad2at_f, &va,
812                         SUPAD2AT_STOP, AVL_INORDER );
813         if ( rc == SUPAD2AT_STOP ) {
814                 return -1;
815         }
816
817         *pret = va.ret;
818
819         return 0;
820 }
821
822 static void
823 backsql_free_attr( void *v_at )
824 {
825         backsql_at_map_rec      *at = v_at;
826         
827         Debug( LDAP_DEBUG_TRACE, "==>free_attr(): \"%s\"\n", 
828                         at->bam_ad->ad_cname.bv_val, 0, 0 );
829         ch_free( at->bam_sel_expr.bv_val );
830         if ( !BER_BVISNULL( &at->bam_from_tbls ) ) {
831                 ch_free( at->bam_from_tbls.bv_val );
832         }
833         if ( !BER_BVISNULL( &at->bam_join_where ) ) {
834                 ch_free( at->bam_join_where.bv_val );
835         }
836         if ( at->bam_add_proc != NULL ) {
837                 ch_free( at->bam_add_proc );
838         }
839         if ( at->bam_delete_proc != NULL ) {
840                 ch_free( at->bam_delete_proc );
841         }
842         if ( at->bam_query != NULL ) {
843                 ch_free( at->bam_query );
844         }
845
846 #ifdef BACKSQL_COUNTQUERY
847         if ( at->bam_countquery != NULL ) {
848                 ch_free( at->bam_countquery );
849         }
850 #endif /* BACKSQL_COUNTQUERY */
851
852         /* TimesTen */
853         if ( !BER_BVISNULL( &at->bam_sel_expr_u ) ) {
854                 ch_free( at->bam_sel_expr_u.bv_val );
855         }
856
857         if ( at->bam_next ) {
858                 backsql_free_attr( at->bam_next );
859         }
860         
861         ch_free( at );
862
863         Debug( LDAP_DEBUG_TRACE, "<==free_attr()\n", 0, 0, 0 );
864 }
865
866 static void
867 backsql_free_oc( void *v_oc )
868 {
869         backsql_oc_map_rec      *oc = v_oc;
870         
871         Debug( LDAP_DEBUG_TRACE, "==>free_oc(): \"%s\"\n", 
872                         BACKSQL_OC_NAME( oc ), 0, 0 );
873         avl_free( oc->bom_attrs, backsql_free_attr );
874         ch_free( oc->bom_keytbl.bv_val );
875         ch_free( oc->bom_keycol.bv_val );
876         if ( oc->bom_create_proc != NULL ) {
877                 ch_free( oc->bom_create_proc );
878         }
879         if ( oc->bom_create_keyval != NULL ) {
880                 ch_free( oc->bom_create_keyval );
881         }
882         if ( oc->bom_delete_proc != NULL ) {
883                 ch_free( oc->bom_delete_proc );
884         }
885         ch_free( oc );
886
887         Debug( LDAP_DEBUG_TRACE, "<==free_oc()\n", 0, 0, 0 );
888 }
889
890 int
891 backsql_destroy_schema_map( backsql_info *bi )
892 {
893         Debug( LDAP_DEBUG_TRACE, "==>destroy_schema_map()\n", 0, 0, 0 );
894         avl_free( bi->sql_oc_by_oc, 0 );
895         avl_free( bi->sql_oc_by_id, backsql_free_oc );
896         Debug( LDAP_DEBUG_TRACE, "<==destroy_schema_map()\n", 0, 0, 0 );
897         return 0;
898 }
899