1 /* $NetBSD: schema-map.c,v 1.1.1.5 2017/02/09 01:47:07 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2016 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.1.1.5 2017/02/09 01:47:07 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 ( 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, 0 ); 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, 0 ); 371 bas->bas_rc = LDAP_OTHER; 372 return BACKSQL_AVL_STOP; 373 } 374 } 375 } 376 377 { 378 char buf[ SLAP_TEXT_BUFLEN ]; 379 380 snprintf( buf, sizeof( buf ), 381 "attributeType: " 382 "name=\"%s\" " 383 "sel_expr=\"%s\" " 384 "from=\"%s\" " 385 "join_where=\"%s\" " 386 "add_proc=\"%s\" " 387 "delete_proc=\"%s\" " 388 "sel_expr_u=\"%s\"", 389 at_row.cols[ 0 ], 390 at_row.cols[ 1 ], 391 at_row.cols[ 2 ], 392 at_row.cols[ 3 ] ? at_row.cols[ 3 ] : "", 393 at_row.cols[ 4 ] ? at_row.cols[ 4 ] : "", 394 at_row.cols[ 5 ] ? at_row.cols[ 5 ] : "", 395 at_row.cols[ 8 ] ? at_row.cols[ 8 ] : ""); 396 Debug( LDAP_DEBUG_TRACE, "%s\n", buf, 0, 0 ); 397 } 398 399 rc = slap_str2ad( at_row.cols[ 0 ], &ad, &text ); 400 if ( rc != LDAP_SUCCESS ) { 401 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): " 402 "attribute \"%s\" for objectClass \"%s\" " 403 "is not defined in schema: %s\n", 404 at_row.cols[ 0 ], 405 BACKSQL_OC_NAME( oc_map ), text ); 406 bas->bas_rc = LDAP_CONSTRAINT_VIOLATION; 407 return BACKSQL_AVL_STOP; 408 } 409 at_map = (backsql_at_map_rec *)ch_calloc( 1, 410 sizeof( backsql_at_map_rec ) ); 411 at_map->bam_ad = ad; 412 at_map->bam_true_ad = ad; 413 if ( slap_syntax_is_binary( ad->ad_type->sat_syntax ) 414 && !slap_ad_is_binary( ad ) ) 415 { 416 char buf[ SLAP_TEXT_BUFLEN ]; 417 struct berval bv; 418 const char *text = NULL; 419 420 bv.bv_val = buf; 421 bv.bv_len = snprintf( buf, sizeof( buf ), "%s;binary", 422 ad->ad_cname.bv_val ); 423 at_map->bam_true_ad = NULL; 424 bas->bas_rc = slap_bv2ad( &bv, &at_map->bam_true_ad, &text ); 425 if ( bas->bas_rc != LDAP_SUCCESS ) { 426 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): " 427 "unable to fetch attribute \"%s\": %s (%d)\n", 428 buf, text, rc ); 429 ch_free( at_map ); 430 return BACKSQL_AVL_STOP; 431 } 432 } 433 434 ber_str2bv( at_row.cols[ 1 ], 0, 1, &at_map->bam_sel_expr ); 435 if ( at_row.value_len[ 8 ] <= 0 ) { 436 BER_BVZERO( &at_map->bam_sel_expr_u ); 437 438 } else { 439 ber_str2bv( at_row.cols[ 8 ], 0, 1, 440 &at_map->bam_sel_expr_u ); 441 } 442 443 ber_str2bv( at_row.cols[ 2 ], 0, 0, &bv ); 444 backsql_merge_from_clause( bas->bas_bi, &bb, &bv ); 445 at_map->bam_from_tbls = bb.bb_val; 446 if ( at_row.value_len[ 3 ] <= 0 ) { 447 BER_BVZERO( &at_map->bam_join_where ); 448 449 } else { 450 ber_str2bv( at_row.cols[ 3 ], 0, 1, 451 &at_map->bam_join_where ); 452 } 453 at_map->bam_add_proc = NULL; 454 if ( at_row.value_len[ 4 ] > 0 ) { 455 at_map->bam_add_proc = ch_strdup( at_row.cols[ 4 ] ); 456 } 457 at_map->bam_delete_proc = NULL; 458 if ( at_row.value_len[ 5 ] > 0 ) { 459 at_map->bam_delete_proc = ch_strdup( at_row.cols[ 5 ] ); 460 } 461 if ( lutil_atoix( &at_map->bam_param_order, at_row.cols[ 6 ], 0 ) != 0 ) { 462 /* error */ 463 } 464 if ( lutil_atoix( &at_map->bam_expect_return, at_row.cols[ 7 ], 0 ) != 0 ) { 465 /* error */ 466 } 467 backsql_make_attr_query( bas->bas_bi, oc_map, at_map ); 468 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): " 469 "preconstructed query \"%s\"\n", 470 at_map->bam_query, 0, 0 ); 471 at_map->bam_next = NULL; 472 if ( avl_insert( &oc_map->bom_attrs, at_map, backsql_cmp_attr, backsql_dup_attr ) == BACKSQL_DUPLICATE ) { 473 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): " 474 "duplicate attribute \"%s\" " 475 "in objectClass \"%s\" map\n", 476 at_map->bam_ad->ad_cname.bv_val, 477 oc_map->bom_oc->soc_cname.bv_val, 0 ); 478 ch_free( at_map ); 479 } 480 481 if ( !BER_BVISNULL( &bas->bas_bi->sql_upper_func ) && 482 BER_BVISNULL( &at_map->bam_sel_expr_u ) ) 483 { 484 struct berbuf bb = BB_NULL; 485 486 backsql_strfcat_x( &bb, NULL, "bcbc", 487 &bas->bas_bi->sql_upper_func, 488 '(' /* ) */ , 489 &at_map->bam_sel_expr, 490 /* ( */ ')' ); 491 at_map->bam_sel_expr_u = bb.bb_val; 492 } 493 } 494 backsql_FreeRow( &at_row ); 495 SQLFreeStmt( bas->bas_sth, SQL_CLOSE ); 496 497 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(\"%s\"): " 498 "autoadding 'objectClass' and 'ref' mappings\n", 499 BACKSQL_OC_NAME( oc_map ), 0, 0 ); 500 501 (void)backsql_add_sysmaps( bas->bas_bi, oc_map ); 502 503 return BACKSQL_AVL_CONTINUE; 504 } 505 506 507 int 508 backsql_load_schema_map( backsql_info *bi, SQLHDBC dbh ) 509 { 510 SQLHSTMT sth = SQL_NULL_HSTMT; 511 RETCODE rc; 512 BACKSQL_ROW_NTS oc_row; 513 backsql_key_t oc_id; 514 backsql_oc_map_rec *oc_map; 515 struct backsql_attr_schema_info bas; 516 517 int delete_proc_idx = 5; 518 int create_hint_idx = delete_proc_idx + 2; 519 520 Debug( LDAP_DEBUG_TRACE, "==>backsql_load_schema_map()\n", 0, 0, 0 ); 521 522 /* 523 * TimesTen : See if the ldap_entries.dn_ru field exists in the schema 524 */ 525 if ( !BACKSQL_DONTCHECK_LDAPINFO_DN_RU( bi ) ) { 526 rc = backsql_Prepare( dbh, &sth, 527 backsql_check_dn_ru_query, 0 ); 528 if ( rc == SQL_SUCCESS ) { 529 /* Yes, the field exists */ 530 bi->sql_flags |= BSQLF_HAS_LDAPINFO_DN_RU; 531 Debug( LDAP_DEBUG_TRACE, "ldapinfo.dn_ru field exists " 532 "in the schema\n", 0, 0, 0 ); 533 } else { 534 /* No such field exists */ 535 bi->sql_flags &= ~BSQLF_HAS_LDAPINFO_DN_RU; 536 } 537 538 SQLFreeStmt( sth, SQL_DROP ); 539 } 540 541 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): oc_query \"%s\"\n", 542 bi->sql_oc_query, 0, 0 ); 543 544 rc = backsql_Prepare( dbh, &sth, bi->sql_oc_query, 0 ); 545 if ( rc != SQL_SUCCESS ) { 546 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): " 547 "error preparing oc_query: \"%s\"\n", 548 bi->sql_oc_query, 0, 0 ); 549 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 550 return LDAP_OTHER; 551 } 552 553 rc = SQLExecute( sth ); 554 if ( rc != SQL_SUCCESS ) { 555 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): " 556 "error executing oc_query: \n", 0, 0, 0 ); 557 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 558 return LDAP_OTHER; 559 } 560 561 backsql_BindRowAsStrings( sth, &oc_row ); 562 rc = SQLFetch( sth ); 563 564 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) { 565 delete_proc_idx++; 566 create_hint_idx++; 567 } 568 569 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) { 570 { 571 struct { 572 int idx; 573 char *name; 574 } required[] = { 575 { 0, "id" }, 576 { 1, "name" }, 577 { 2, "keytbl" }, 578 { 3, "keycol" }, 579 { -1, "expect_return" }, 580 { -1, NULL }, 581 }; 582 int i; 583 584 required[4].idx = delete_proc_idx + 1; 585 586 for ( i = 0; required[ i ].name != NULL; i++ ) { 587 if ( oc_row.value_len[ required[ i ].idx ] <= 0 ) { 588 Debug( LDAP_DEBUG_ANY, 589 "backsql_load_schema_map(): " 590 "required column #%d \"%s\" is empty\n", 591 required[ i ].idx, required[ i ].name, 0 ); 592 return LDAP_OTHER; 593 } 594 } 595 } 596 597 { 598 char buf[ SLAP_TEXT_BUFLEN ]; 599 600 snprintf( buf, sizeof( buf ), 601 "objectClass: " 602 "id=\"%s\" " 603 "name=\"%s\" " 604 "keytbl=\"%s\" " 605 "keycol=\"%s\" " 606 "create_proc=\"%s\" " 607 "create_keyval=\"%s\" " 608 "delete_proc=\"%s\" " 609 "expect_return=\"%s\"" 610 "create_hint=\"%s\" ", 611 oc_row.cols[ 0 ], 612 oc_row.cols[ 1 ], 613 oc_row.cols[ 2 ], 614 oc_row.cols[ 3 ], 615 oc_row.cols[ 4 ] ? oc_row.cols[ 4 ] : "", 616 ( BACKSQL_CREATE_NEEDS_SELECT( bi ) && oc_row.cols[ 5 ] ) ? oc_row.cols[ 5 ] : "", 617 oc_row.cols[ delete_proc_idx ] ? oc_row.cols[ delete_proc_idx ] : "", 618 oc_row.cols[ delete_proc_idx + 1 ], 619 ( ( oc_row.ncols > create_hint_idx ) && oc_row.cols[ create_hint_idx ] ) ? oc_row.cols[ create_hint_idx ] : "" ); 620 Debug( LDAP_DEBUG_TRACE, "%s\n", buf, 0, 0 ); 621 } 622 623 oc_map = (backsql_oc_map_rec *)ch_calloc( 1, 624 sizeof( backsql_oc_map_rec ) ); 625 626 if ( BACKSQL_STR2ID( &oc_map->bom_id, oc_row.cols[ 0 ], 0 ) != 0 ) { 627 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): " 628 "unable to parse id=\"%s\"\n", 629 oc_row.cols[ 0 ], 0, 0 ); 630 ch_free( oc_map ); 631 return LDAP_OTHER; 632 } 633 634 oc_map->bom_oc = oc_find( oc_row.cols[ 1 ] ); 635 if ( oc_map->bom_oc == NULL ) { 636 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): " 637 "objectClass \"%s\" is not defined in schema\n", 638 oc_row.cols[ 1 ], 0, 0 ); 639 ch_free( oc_map ); 640 return LDAP_OTHER; /* undefined objectClass ? */ 641 } 642 643 ber_str2bv( oc_row.cols[ 2 ], 0, 1, &oc_map->bom_keytbl ); 644 ber_str2bv( oc_row.cols[ 3 ], 0, 1, &oc_map->bom_keycol ); 645 oc_map->bom_create_proc = ( oc_row.value_len[ 4 ] <= 0 ) ? NULL 646 : ch_strdup( oc_row.cols[ 4 ] ); 647 648 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) { 649 oc_map->bom_create_keyval = ( oc_row.value_len[ 5 ] <= 0 ) 650 ? NULL : ch_strdup( oc_row.cols[ 5 ] ); 651 } 652 oc_map->bom_delete_proc = ( oc_row.value_len[ delete_proc_idx ] <= 0 ) ? NULL 653 : ch_strdup( oc_row.cols[ delete_proc_idx ] ); 654 if ( lutil_atoix( &oc_map->bom_expect_return, oc_row.cols[ delete_proc_idx + 1 ], 0 ) != 0 ) { 655 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): " 656 "unable to parse expect_return=\"%s\" for objectClass \"%s\"\n", 657 oc_row.cols[ delete_proc_idx + 1 ], oc_row.cols[ 1 ], 0 ); 658 ch_free( oc_map ); 659 return LDAP_OTHER; 660 } 661 662 if ( ( oc_row.ncols > create_hint_idx ) && 663 ( oc_row.value_len[ create_hint_idx ] > 0 ) ) 664 { 665 const char *text; 666 667 oc_map->bom_create_hint = NULL; 668 rc = slap_str2ad( oc_row.cols[ create_hint_idx ], 669 &oc_map->bom_create_hint, &text ); 670 if ( rc != SQL_SUCCESS ) { 671 Debug( LDAP_DEBUG_TRACE, "load_schema_map(): " 672 "error matching " 673 "AttributeDescription %s " 674 "in create_hint: %s (%d)\n", 675 oc_row.cols[ create_hint_idx ], 676 text, rc ); 677 backsql_PrintErrors( bi->sql_db_env, dbh, 678 sth, rc ); 679 ch_free( oc_map ); 680 return LDAP_OTHER; 681 } 682 } 683 684 /* 685 * FIXME: first attempt to check for offending 686 * instructions in {create|delete}_proc 687 */ 688 689 oc_map->bom_attrs = NULL; 690 if ( avl_insert( &bi->sql_oc_by_oc, oc_map, backsql_cmp_oc, avl_dup_error ) == -1 ) { 691 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): " 692 "duplicate objectClass \"%s\" in objectClass map\n", 693 oc_map->bom_oc->soc_cname.bv_val, 0, 0 ); 694 ch_free( oc_map ); 695 return LDAP_OTHER; 696 } 697 if ( avl_insert( &bi->sql_oc_by_id, oc_map, backsql_cmp_oc_id, avl_dup_error ) == -1 ) { 698 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): " 699 "duplicate objectClass \"%s\" in objectClass by ID map\n", 700 oc_map->bom_oc->soc_cname.bv_val, 0, 0 ); 701 return LDAP_OTHER; 702 } 703 oc_id = oc_map->bom_id; 704 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): " 705 "objectClass \"%s\":\n keytbl=\"%s\" keycol=\"%s\"\n", 706 BACKSQL_OC_NAME( oc_map ), 707 oc_map->bom_keytbl.bv_val, oc_map->bom_keycol.bv_val ); 708 if ( oc_map->bom_create_proc ) { 709 Debug( LDAP_DEBUG_TRACE, " create_proc=\"%s\"\n", 710 oc_map->bom_create_proc, 0, 0 ); 711 } 712 if ( oc_map->bom_create_keyval ) { 713 Debug( LDAP_DEBUG_TRACE, " create_keyval=\"%s\"\n", 714 oc_map->bom_create_keyval, 0, 0 ); 715 } 716 if ( oc_map->bom_create_hint ) { 717 Debug( LDAP_DEBUG_TRACE, " create_hint=\"%s\"\n", 718 oc_map->bom_create_hint->ad_cname.bv_val, 719 0, 0 ); 720 } 721 if ( oc_map->bom_delete_proc ) { 722 Debug( LDAP_DEBUG_TRACE, " delete_proc=\"%s\"\n", 723 oc_map->bom_delete_proc, 0, 0 ); 724 } 725 Debug( LDAP_DEBUG_TRACE, " expect_return: " 726 "add=%d, del=%d; attributes:\n", 727 BACKSQL_IS_ADD( oc_map->bom_expect_return ), 728 BACKSQL_IS_DEL( oc_map->bom_expect_return ), 0 ); 729 } 730 731 backsql_FreeRow( &oc_row ); 732 SQLFreeStmt( sth, SQL_DROP ); 733 734 /* prepare for attribute fetching */ 735 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): at_query \"%s\"\n", 736 bi->sql_at_query, 0, 0 ); 737 738 rc = backsql_Prepare( dbh, &sth, bi->sql_at_query, 0 ); 739 if ( rc != SQL_SUCCESS ) { 740 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): " 741 "error preparing at_query: \"%s\"\n", 742 bi->sql_at_query, 0, 0 ); 743 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 744 return LDAP_OTHER; 745 } 746 747 rc = backsql_BindParamNumID( sth, 1, SQL_PARAM_INPUT, &oc_id ); 748 if ( rc != SQL_SUCCESS ) { 749 Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): " 750 "error binding param \"oc_id\" for at_query\n", 0, 0, 0 ); 751 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 752 SQLFreeStmt( sth, SQL_DROP ); 753 return LDAP_OTHER; 754 } 755 756 bas.bas_bi = bi; 757 bas.bas_dbh = dbh; 758 bas.bas_sth = sth; 759 bas.bas_oc_id = &oc_id; 760 bas.bas_rc = LDAP_SUCCESS; 761 762 (void)avl_apply( bi->sql_oc_by_oc, backsql_oc_get_attr_mapping, 763 &bas, BACKSQL_AVL_STOP, AVL_INORDER ); 764 765 SQLFreeStmt( sth, SQL_DROP ); 766 767 bi->sql_flags |= BSQLF_SCHEMA_LOADED; 768 769 Debug( LDAP_DEBUG_TRACE, "<==backsql_load_schema_map()\n", 0, 0, 0 ); 770 771 return bas.bas_rc; 772 } 773 774 backsql_oc_map_rec * 775 backsql_oc2oc( backsql_info *bi, ObjectClass *oc ) 776 { 777 backsql_oc_map_rec tmp, *res; 778 779 #ifdef BACKSQL_TRACE 780 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc2oc(): " 781 "searching for objectclass with name=\"%s\"\n", 782 oc->soc_cname.bv_val, 0, 0 ); 783 #endif /* BACKSQL_TRACE */ 784 785 tmp.bom_oc = oc; 786 res = (backsql_oc_map_rec *)avl_find( bi->sql_oc_by_oc, &tmp, backsql_cmp_oc ); 787 #ifdef BACKSQL_TRACE 788 if ( res != NULL ) { 789 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): " 790 "found name=\"%s\", id=%d\n", 791 BACKSQL_OC_NAME( res ), res->bom_id, 0 ); 792 } else { 793 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): " 794 "not found\n", 0, 0, 0 ); 795 } 796 #endif /* BACKSQL_TRACE */ 797 798 return res; 799 } 800 801 backsql_oc_map_rec * 802 backsql_name2oc( backsql_info *bi, struct berval *oc_name ) 803 { 804 backsql_oc_map_rec tmp, *res; 805 806 #ifdef BACKSQL_TRACE 807 Debug( LDAP_DEBUG_TRACE, "==>oc_with_name(): " 808 "searching for objectclass with name=\"%s\"\n", 809 oc_name->bv_val, 0, 0 ); 810 #endif /* BACKSQL_TRACE */ 811 812 tmp.bom_oc = oc_bvfind( oc_name ); 813 if ( tmp.bom_oc == NULL ) { 814 return NULL; 815 } 816 817 res = (backsql_oc_map_rec *)avl_find( bi->sql_oc_by_oc, &tmp, backsql_cmp_oc ); 818 #ifdef BACKSQL_TRACE 819 if ( res != NULL ) { 820 Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): " 821 "found name=\"%s\", id=%d\n", 822 BACKSQL_OC_NAME( res ), res->bom_id, 0 ); 823 } else { 824 Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): " 825 "not found\n", 0, 0, 0 ); 826 } 827 #endif /* BACKSQL_TRACE */ 828 829 return res; 830 } 831 832 backsql_oc_map_rec * 833 backsql_id2oc( backsql_info *bi, unsigned long id ) 834 { 835 backsql_oc_map_rec tmp, *res; 836 837 #ifdef BACKSQL_TRACE 838 Debug( LDAP_DEBUG_TRACE, "==>oc_with_id(): " 839 "searching for objectclass with id=%lu\n", id, 0, 0 ); 840 #endif /* BACKSQL_TRACE */ 841 842 tmp.bom_id = id; 843 res = (backsql_oc_map_rec *)avl_find( bi->sql_oc_by_id, &tmp, 844 backsql_cmp_oc_id ); 845 846 #ifdef BACKSQL_TRACE 847 if ( res != NULL ) { 848 Debug( LDAP_DEBUG_TRACE, "<==oc_with_id(): " 849 "found name=\"%s\", id=%lu\n", 850 BACKSQL_OC_NAME( res ), res->bom_id, 0 ); 851 } else { 852 Debug( LDAP_DEBUG_TRACE, "<==oc_with_id(): " 853 "id=%lu not found\n", res->bom_id, 0, 0 ); 854 } 855 #endif /* BACKSQL_TRACE */ 856 857 return res; 858 } 859 860 backsql_at_map_rec * 861 backsql_ad2at( backsql_oc_map_rec* objclass, AttributeDescription *ad ) 862 { 863 backsql_at_map_rec tmp = { 0 }, *res; 864 865 #ifdef BACKSQL_TRACE 866 Debug( LDAP_DEBUG_TRACE, "==>backsql_ad2at(): " 867 "searching for attribute \"%s\" for objectclass \"%s\"\n", 868 ad->ad_cname.bv_val, BACKSQL_OC_NAME( objclass ), 0 ); 869 #endif /* BACKSQL_TRACE */ 870 871 tmp.bam_ad = ad; 872 res = (backsql_at_map_rec *)avl_find( objclass->bom_attrs, &tmp, 873 backsql_cmp_attr ); 874 875 #ifdef BACKSQL_TRACE 876 if ( res != NULL ) { 877 Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): " 878 "found name=\"%s\", sel_expr=\"%s\"\n", 879 res->bam_ad->ad_cname.bv_val, 880 res->bam_sel_expr.bv_val, 0 ); 881 } else { 882 Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): " 883 "not found\n", 0, 0, 0 ); 884 } 885 #endif /* BACKSQL_TRACE */ 886 887 return res; 888 } 889 890 /* attributeType inheritance */ 891 struct supad2at_t { 892 backsql_at_map_rec **ret; 893 AttributeDescription *ad; 894 unsigned n; 895 }; 896 897 #define SUPAD2AT_STOP (-1) 898 899 static int 900 supad2at_f( void *v_at, void *v_arg ) 901 { 902 backsql_at_map_rec *at = (backsql_at_map_rec *)v_at; 903 struct supad2at_t *va = (struct supad2at_t *)v_arg; 904 905 if ( is_at_subtype( at->bam_ad->ad_type, va->ad->ad_type ) ) { 906 backsql_at_map_rec **ret = NULL; 907 unsigned i; 908 909 /* if already listed, holler! (should never happen) */ 910 if ( va->ret ) { 911 for ( i = 0; i < va->n; i++ ) { 912 if ( va->ret[ i ]->bam_ad == at->bam_ad ) { 913 break; 914 } 915 } 916 917 if ( i < va->n ) { 918 return 0; 919 } 920 } 921 922 ret = ch_realloc( va->ret, 923 sizeof( backsql_at_map_rec * ) * ( va->n + 2 ) ); 924 if ( ret == NULL ) { 925 ch_free( va->ret ); 926 va->ret = NULL; 927 va->n = 0; 928 return SUPAD2AT_STOP; 929 } 930 931 ret[ va->n ] = at; 932 va->n++; 933 ret[ va->n ] = NULL; 934 va->ret = ret; 935 } 936 937 return 0; 938 } 939 940 /* 941 * stores in *pret a NULL terminated array of pointers 942 * to backsql_at_map_rec whose attributeType is supad->ad_type 943 * or derived from it 944 */ 945 int 946 backsql_supad2at( backsql_oc_map_rec *objclass, AttributeDescription *supad, 947 backsql_at_map_rec ***pret ) 948 { 949 struct supad2at_t va = { 0 }; 950 int rc; 951 952 assert( objclass != NULL ); 953 assert( supad != NULL ); 954 assert( pret != NULL ); 955 956 *pret = NULL; 957 958 va.ad = supad; 959 960 rc = avl_apply( objclass->bom_attrs, supad2at_f, &va, 961 SUPAD2AT_STOP, AVL_INORDER ); 962 if ( rc == SUPAD2AT_STOP ) { 963 return -1; 964 } 965 966 *pret = va.ret; 967 968 return 0; 969 } 970 971 static void 972 backsql_free_attr( void *v_at ) 973 { 974 backsql_at_map_rec *at = v_at; 975 976 Debug( LDAP_DEBUG_TRACE, "==>free_attr(): \"%s\"\n", 977 at->bam_ad->ad_cname.bv_val, 0, 0 ); 978 ch_free( at->bam_sel_expr.bv_val ); 979 if ( !BER_BVISNULL( &at->bam_from_tbls ) ) { 980 ch_free( at->bam_from_tbls.bv_val ); 981 } 982 if ( !BER_BVISNULL( &at->bam_join_where ) ) { 983 ch_free( at->bam_join_where.bv_val ); 984 } 985 if ( at->bam_add_proc != NULL ) { 986 ch_free( at->bam_add_proc ); 987 } 988 if ( at->bam_delete_proc != NULL ) { 989 ch_free( at->bam_delete_proc ); 990 } 991 if ( at->bam_query != NULL ) { 992 ch_free( at->bam_query ); 993 } 994 995 #ifdef BACKSQL_COUNTQUERY 996 if ( at->bam_countquery != NULL ) { 997 ch_free( at->bam_countquery ); 998 } 999 #endif /* BACKSQL_COUNTQUERY */ 1000 1001 /* TimesTen */ 1002 if ( !BER_BVISNULL( &at->bam_sel_expr_u ) ) { 1003 ch_free( at->bam_sel_expr_u.bv_val ); 1004 } 1005 1006 if ( at->bam_next ) { 1007 backsql_free_attr( at->bam_next ); 1008 } 1009 1010 ch_free( at ); 1011 1012 Debug( LDAP_DEBUG_TRACE, "<==free_attr()\n", 0, 0, 0 ); 1013 } 1014 1015 static void 1016 backsql_free_oc( void *v_oc ) 1017 { 1018 backsql_oc_map_rec *oc = v_oc; 1019 1020 Debug( LDAP_DEBUG_TRACE, "==>free_oc(): \"%s\"\n", 1021 BACKSQL_OC_NAME( oc ), 0, 0 ); 1022 avl_free( oc->bom_attrs, backsql_free_attr ); 1023 ch_free( oc->bom_keytbl.bv_val ); 1024 ch_free( oc->bom_keycol.bv_val ); 1025 if ( oc->bom_create_proc != NULL ) { 1026 ch_free( oc->bom_create_proc ); 1027 } 1028 if ( oc->bom_create_keyval != NULL ) { 1029 ch_free( oc->bom_create_keyval ); 1030 } 1031 if ( oc->bom_delete_proc != NULL ) { 1032 ch_free( oc->bom_delete_proc ); 1033 } 1034 ch_free( oc ); 1035 1036 Debug( LDAP_DEBUG_TRACE, "<==free_oc()\n", 0, 0, 0 ); 1037 } 1038 1039 int 1040 backsql_destroy_schema_map( backsql_info *bi ) 1041 { 1042 Debug( LDAP_DEBUG_TRACE, "==>destroy_schema_map()\n", 0, 0, 0 ); 1043 avl_free( bi->sql_oc_by_oc, 0 ); 1044 avl_free( bi->sql_oc_by_id, backsql_free_oc ); 1045 Debug( LDAP_DEBUG_TRACE, "<==destroy_schema_map()\n", 0, 0, 0 ); 1046 return 0; 1047 } 1048 1049