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