Back to index

openldap  2.4.31
schema-map.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1999-2012 The OpenLDAP Foundation.
00005  * Portions Copyright 1999 Dmitry Kovalev.
00006  * Portions Copyright 2002 Pierangelo Masarati.
00007  * Portions Copyright 2004 Mark Adamson.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted only as authorized by the OpenLDAP
00012  * Public License.
00013  *
00014  * A copy of this license is available in the file LICENSE in the
00015  * top-level directory of the distribution or, alternatively, at
00016  * <http://www.OpenLDAP.org/license.html>.
00017  */
00018 /* ACKNOWLEDGEMENTS:
00019  * This work was initially developed by Dmitry Kovalev for inclusion
00020  * by OpenLDAP Software.  Additional significant contributors include
00021  * Pierangelo Masarati and Mark Adamson.
00022  */
00023 
00024 #include "portable.h"
00025 
00026 #include <stdio.h>
00027 #include <sys/types.h>
00028 #include "ac/string.h"
00029 
00030 #include "lutil.h"
00031 #include "slap.h"
00032 #include "proto-sql.h"
00033 
00034 #define BACKSQL_DUPLICATE   (-1)
00035 
00036 /* NOTE: by default, cannot just compare pointers because
00037  * objectClass/attributeType order would be machine-dependent
00038  * (and tests would fail!); however, if you don't want to run
00039  * tests, or see attributeTypes written in the same order
00040  * they are defined, define */
00041 /* #undef BACKSQL_USE_PTR_CMP */
00042 
00043 /*
00044  * Uses the pointer to the ObjectClass structure
00045  */
00046 static int
00047 backsql_cmp_oc( const void *v_m1, const void *v_m2 )
00048 {
00049        const backsql_oc_map_rec    *m1 = v_m1,
00050                                    *m2 = v_m2;
00051 
00052 #ifdef BACKSQL_USE_PTR_CMP
00053        return SLAP_PTRCMP( m1->bom_oc, m2->bom_oc );
00054 #else /* ! BACKSQL_USE_PTR_CMP */
00055        return ber_bvcmp( &m1->bom_oc->soc_cname, &m2->bom_oc->soc_cname );
00056 #endif /* ! BACKSQL_USE_PTR_CMP */
00057 }
00058 
00059 static int
00060 backsql_cmp_oc_id( const void *v_m1, const void *v_m2 )
00061 {
00062        const backsql_oc_map_rec    *m1 = v_m1,
00063                                    *m2 = v_m2;
00064 
00065        return ( m1->bom_id < m2->bom_id ? -1 : ( m1->bom_id > m2->bom_id ? 1 : 0 ) );
00066 }
00067 
00068 /*
00069  * Uses the pointer to the AttributeDescription structure
00070  */
00071 static int
00072 backsql_cmp_attr( const void *v_m1, const void *v_m2 )
00073 {
00074        const backsql_at_map_rec    *m1 = v_m1,
00075                                    *m2 = v_m2;
00076 
00077        if ( slap_ad_is_binary( m1->bam_ad ) || slap_ad_is_binary( m2->bam_ad ) ) {
00078 #ifdef BACKSQL_USE_PTR_CMP
00079               return SLAP_PTRCMP( m1->bam_ad->ad_type, m2->bam_ad->ad_type );
00080 #else /* ! BACKSQL_USE_PTR_CMP */
00081               return ber_bvcmp( &m1->bam_ad->ad_type->sat_cname, &m2->bam_ad->ad_type->sat_cname );
00082 #endif /* ! BACKSQL_USE_PTR_CMP */
00083        }
00084 
00085 #ifdef BACKSQL_USE_PTR_CMP
00086        return SLAP_PTRCMP( m1->bam_ad, m2->bam_ad );
00087 #else /* ! BACKSQL_USE_PTR_CMP */
00088        return ber_bvcmp( &m1->bam_ad->ad_cname, &m2->bam_ad->ad_cname );
00089 #endif /* ! BACKSQL_USE_PTR_CMP */
00090 }
00091 
00092 int
00093 backsql_dup_attr( void *v_m1, void *v_m2 )
00094 {
00095        backsql_at_map_rec          *m1 = v_m1,
00096                                    *m2 = v_m2;
00097 
00098        if ( slap_ad_is_binary( m1->bam_ad ) || slap_ad_is_binary( m2->bam_ad ) ) {
00099 #ifdef BACKSQL_USE_PTR_CMP
00100               assert( m1->bam_ad->ad_type == m2->bam_ad->ad_type );
00101 #else /* ! BACKSQL_USE_PTR_CMP */
00102               assert( ber_bvcmp( &m1->bam_ad->ad_type->sat_cname, &m2->bam_ad->ad_type->sat_cname ) == 0 );
00103 #endif /* ! BACKSQL_USE_PTR_CMP */
00104 
00105        } else {
00106 #ifdef BACKSQL_USE_PTR_CMP
00107               assert( m1->bam_ad == m2->bam_ad );
00108 #else /* ! BACKSQL_USE_PTR_CMP */
00109               assert( ber_bvcmp( &m1->bam_ad->ad_cname, &m2->bam_ad->ad_cname ) == 0 );
00110 #endif /* ! BACKSQL_USE_PTR_CMP */
00111        }
00112 
00113        /* duplicate definitions of attributeTypes are appended;
00114         * this allows to define multiple rules for the same 
00115         * attributeType.  Use with care! */
00116        for ( ; m1->bam_next ; m1 = m1->bam_next );
00117 
00118        m1->bam_next = m2;
00119        m2->bam_next = NULL;
00120 
00121        return BACKSQL_DUPLICATE;
00122 }
00123 
00124 static int
00125 backsql_make_attr_query( 
00126        backsql_info         *bi,
00127        backsql_oc_map_rec   *oc_map,
00128        backsql_at_map_rec   *at_map )
00129 {
00130        struct berbuf bb = BB_NULL;
00131 
00132        backsql_strfcat_x( &bb, NULL, "lblbbbblblbcbl", 
00133                      (ber_len_t)STRLENOF( "SELECT " ), "SELECT ", 
00134                      &at_map->bam_sel_expr, 
00135                      (ber_len_t)STRLENOF( " " ), " ",
00136                      &bi->sql_aliasing,
00137                      &bi->sql_aliasing_quote, 
00138                      &at_map->bam_ad->ad_cname,
00139                      &bi->sql_aliasing_quote,
00140                      (ber_len_t)STRLENOF( " FROM " ), " FROM ", 
00141                      &at_map->bam_from_tbls, 
00142                      (ber_len_t)STRLENOF( " WHERE " ), " WHERE ", 
00143                      &oc_map->bom_keytbl,
00144                      '.', 
00145                      &oc_map->bom_keycol,
00146                      (ber_len_t)STRLENOF( "=?" ), "=?" );
00147 
00148        if ( !BER_BVISNULL( &at_map->bam_join_where ) ) {
00149               backsql_strfcat_x( &bb, NULL, "lb",
00150                             (ber_len_t)STRLENOF( " AND " ), " AND ", 
00151                             &at_map->bam_join_where );
00152        }
00153 
00154        backsql_strfcat_x( &bb, NULL, "lbbb", 
00155                      (ber_len_t)STRLENOF( " ORDER BY " ), " ORDER BY ",
00156                      &bi->sql_aliasing_quote,
00157                      &at_map->bam_ad->ad_cname,
00158                      &bi->sql_aliasing_quote );
00159 
00160        at_map->bam_query = bb.bb_val.bv_val;
00161 
00162 #ifdef BACKSQL_COUNTQUERY
00163        /* Query to count how many rows will be returned.
00164 
00165        SELECT COUNT(*) FROM <from_tbls> WHERE <keytbl>.<keycol>=?
00166               [ AND <join_where> ]
00167 
00168         */
00169        BER_BVZERO( &bb.bb_val );
00170        bb.bb_len = 0;
00171        backsql_strfcat_x( &bb, NULL, "lblbcbl", 
00172                      (ber_len_t)STRLENOF( "SELECT COUNT(*) FROM " ),
00173                             "SELECT COUNT(*) FROM ", 
00174                      &at_map->bam_from_tbls, 
00175                      (ber_len_t)STRLENOF( " WHERE " ), " WHERE ", 
00176                      &oc_map->bom_keytbl,
00177                      '.', 
00178                      &oc_map->bom_keycol,
00179                      (ber_len_t)STRLENOF( "=?" ), "=?" );
00180 
00181        if ( !BER_BVISNULL( &at_map->bam_join_where ) ) {
00182               backsql_strfcat_x( &bb, NULL, "lb",
00183                             (ber_len_t)STRLENOF( " AND " ), " AND ", 
00184                             &at_map->bam_join_where );
00185        }
00186 
00187        at_map->bam_countquery = bb.bb_val.bv_val;
00188 #endif /* BACKSQL_COUNTQUERY */
00189 
00190        return 0;
00191 }
00192 
00193 static int
00194 backsql_add_sysmaps( backsql_info *bi, backsql_oc_map_rec *oc_map )
00195 {
00196        backsql_at_map_rec   *at_map;
00197        char                 s[LDAP_PVT_INTTYPE_CHARS(long)];
00198        struct berval        sbv;
00199        struct berbuf        bb;
00200        
00201        sbv.bv_val = s;
00202        sbv.bv_len = snprintf( s, sizeof( s ), BACKSQL_IDNUMFMT, oc_map->bom_id );
00203 
00204        /* extra objectClasses */
00205        at_map = (backsql_at_map_rec *)ch_calloc(1, 
00206                      sizeof( backsql_at_map_rec ) );
00207        at_map->bam_ad = slap_schema.si_ad_objectClass;
00208        at_map->bam_true_ad = slap_schema.si_ad_objectClass;
00209        ber_str2bv( "ldap_entry_objclasses.oc_name", 0, 1,
00210                      &at_map->bam_sel_expr );
00211        ber_str2bv( "ldap_entry_objclasses,ldap_entries", 0, 1, 
00212                      &at_map->bam_from_tbls );
00213        
00214        bb.bb_len = at_map->bam_from_tbls.bv_len + 1;
00215        bb.bb_val = at_map->bam_from_tbls;
00216        backsql_merge_from_clause( bi, &bb, &oc_map->bom_keytbl );
00217        at_map->bam_from_tbls = bb.bb_val;
00218 
00219        BER_BVZERO( &bb.bb_val );
00220        bb.bb_len = 0;
00221        backsql_strfcat_x( &bb, NULL, "lbcblb",
00222                      (ber_len_t)STRLENOF( "ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entries.keyval=" ),
00223                             "ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entries.keyval=",
00224                      &oc_map->bom_keytbl, 
00225                      '.', 
00226                      &oc_map->bom_keycol,
00227                      (ber_len_t)STRLENOF( " and ldap_entries.oc_map_id=" ), 
00228                             " and ldap_entries.oc_map_id=", 
00229                      &sbv );
00230        at_map->bam_join_where = bb.bb_val;
00231 
00232        at_map->bam_oc = oc_map->bom_oc;
00233 
00234        at_map->bam_add_proc = NULL;
00235        {
00236               char   tmp[STRLENOF("INSERT INTO ldap_entry_objclasses "
00237                      "(entry_id,oc_name) VALUES "
00238                      "((SELECT id FROM ldap_entries "
00239                      "WHERE oc_map_id= "
00240                      "AND keyval=?),?)") + LDAP_PVT_INTTYPE_CHARS(unsigned long)];
00241               snprintf( tmp, sizeof(tmp), 
00242                      "INSERT INTO ldap_entry_objclasses "
00243                      "(entry_id,oc_name) VALUES "
00244                      "((SELECT id FROM ldap_entries "
00245                      "WHERE oc_map_id=" BACKSQL_IDNUMFMT " "
00246                      "AND keyval=?),?)", oc_map->bom_id );
00247               at_map->bam_add_proc = ch_strdup( tmp );
00248        }
00249 
00250        at_map->bam_delete_proc = NULL;
00251        {
00252               char   tmp[STRLENOF("DELETE FROM ldap_entry_objclasses "
00253                      "WHERE entry_id=(SELECT id FROM ldap_entries "
00254                      "WHERE oc_map_id= "
00255                      "AND keyval=?) AND oc_name=?") + LDAP_PVT_INTTYPE_CHARS(unsigned long)];
00256               snprintf( tmp, sizeof(tmp), 
00257                      "DELETE FROM ldap_entry_objclasses "
00258                      "WHERE entry_id=(SELECT id FROM ldap_entries "
00259                      "WHERE oc_map_id=" BACKSQL_IDNUMFMT " "
00260                      "AND keyval=?) AND oc_name=?",
00261                      oc_map->bom_id );
00262               at_map->bam_delete_proc = ch_strdup( tmp );
00263        }
00264 
00265        at_map->bam_param_order = 0;
00266        at_map->bam_expect_return = 0;
00267        at_map->bam_next = NULL;
00268 
00269        backsql_make_attr_query( bi, oc_map, at_map );
00270        if ( avl_insert( &oc_map->bom_attrs, at_map, backsql_cmp_attr, backsql_dup_attr ) == BACKSQL_DUPLICATE ) {
00271               Debug( LDAP_DEBUG_TRACE, "backsql_add_sysmaps(): "
00272                             "duplicate attribute \"%s\" in objectClass \"%s\" map\n",
00273                             at_map->bam_ad->ad_cname.bv_val,
00274                             oc_map->bom_oc->soc_cname.bv_val, 0 );
00275        }
00276 
00277        /* FIXME: we need to correct the objectClass join_where 
00278         * after the attribute query is built */
00279        ch_free( at_map->bam_join_where.bv_val );
00280        BER_BVZERO( &bb.bb_val );
00281        bb.bb_len = 0;
00282        backsql_strfcat_x( &bb, NULL, "lbcblb",
00283                      (ber_len_t)STRLENOF( /* "ldap_entries.id=ldap_entry_objclasses.entry_id AND " */ "ldap_entries.keyval=" ),
00284                             /* "ldap_entries.id=ldap_entry_objclasses.entry_id AND " */ "ldap_entries.keyval=",
00285                      &oc_map->bom_keytbl, 
00286                      '.', 
00287                      &oc_map->bom_keycol,
00288                      (ber_len_t)STRLENOF( " AND ldap_entries.oc_map_id=" ), 
00289                             " AND ldap_entries.oc_map_id=", 
00290                      &sbv );
00291        at_map->bam_join_where = bb.bb_val;
00292 
00293        return 1;
00294 }
00295 
00296 struct backsql_attr_schema_info {
00297        backsql_info  *bas_bi;
00298        SQLHDBC              bas_dbh;
00299        SQLHSTMT      bas_sth;
00300        backsql_key_t *bas_oc_id;
00301        int           bas_rc;
00302 };
00303 
00304 static int
00305 backsql_oc_get_attr_mapping( void *v_oc, void *v_bas )
00306 {
00307        RETCODE                            rc;
00308        BACKSQL_ROW_NTS                    at_row;
00309        backsql_oc_map_rec          *oc_map = (backsql_oc_map_rec *)v_oc;
00310        backsql_at_map_rec          *at_map;
00311        struct backsql_attr_schema_info    *bas = (struct backsql_attr_schema_info *)v_bas;
00312 
00313        /* bas->bas_oc_id has been bound to bas->bas_sth */
00314        *bas->bas_oc_id = oc_map->bom_id;
00315 
00316        Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
00317               "executing at_query\n"
00318               "    \"%s\"\n"
00319               "    for objectClass \"%s\"\n"
00320               "    with param oc_id=" BACKSQL_IDNUMFMT "\n",
00321               bas->bas_bi->sql_at_query,
00322               BACKSQL_OC_NAME( oc_map ),
00323               *bas->bas_oc_id );
00324 
00325        rc = SQLExecute( bas->bas_sth );
00326        if ( rc != SQL_SUCCESS ) {
00327               Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
00328                      "error executing at_query\n"
00329                      "    \"%s\"\n"
00330                      "    for objectClass \"%s\"\n"
00331                      "    with param oc_id=" BACKSQL_IDNUMFMT "\n",
00332                      bas->bas_bi->sql_at_query,
00333                      BACKSQL_OC_NAME( oc_map ),
00334                      *bas->bas_oc_id );
00335               backsql_PrintErrors( bas->bas_bi->sql_db_env,
00336                             bas->bas_dbh, bas->bas_sth, rc );
00337               bas->bas_rc = LDAP_OTHER;
00338               return BACKSQL_AVL_STOP;
00339        }
00340 
00341        backsql_BindRowAsStrings( bas->bas_sth, &at_row );
00342        for ( ; rc = SQLFetch( bas->bas_sth ), BACKSQL_SUCCESS( rc ); ) {
00343               const char    *text = NULL;
00344               struct berval bv;
00345               struct berbuf bb = BB_NULL;
00346               AttributeDescription *ad = NULL;
00347 
00348               {
00349                      struct {
00350                             int idx;
00351                             char *name;
00352                      } required[] = {
00353                             { 0, "name" },
00354                             { 1, "sel_expr" },
00355                             { 2, "from" },
00356                             { -1, NULL },
00357                      };
00358                      int i;
00359 
00360                      for ( i = 0; required[ i ].name != NULL; i++ ) {
00361                             if ( at_row.value_len[ i ] <= 0 ) {
00362                                    Debug( LDAP_DEBUG_ANY,
00363                                           "backsql_oc_get_attr_mapping(): "
00364                                           "required column #%d \"%s\" is empty\n",
00365                                           required[ i ].idx, required[ i ].name, 0 );
00366                                    bas->bas_rc = LDAP_OTHER;
00367                                    return BACKSQL_AVL_STOP;
00368                             }
00369                      }
00370               }
00371 
00372               {
00373                      char          buf[ SLAP_TEXT_BUFLEN ];
00374 
00375                      snprintf( buf, sizeof( buf ),
00376                             "attributeType: "
00377                             "name=\"%s\" "
00378                             "sel_expr=\"%s\" "
00379                             "from=\"%s\" "
00380                             "join_where=\"%s\" "
00381                             "add_proc=\"%s\" "
00382                             "delete_proc=\"%s\" "
00383                             "sel_expr_u=\"%s\"",
00384                             at_row.cols[ 0 ],
00385                             at_row.cols[ 1 ],
00386                             at_row.cols[ 2 ],
00387                             at_row.cols[ 3 ] ? at_row.cols[ 3 ] : "",
00388                             at_row.cols[ 4 ] ? at_row.cols[ 4 ] : "",
00389                             at_row.cols[ 5 ] ? at_row.cols[ 5 ] : "",
00390                             at_row.cols[ 8 ] ? at_row.cols[ 8 ] : "");
00391                      Debug( LDAP_DEBUG_TRACE, "%s\n", buf, 0, 0 );
00392               }
00393 
00394               rc = slap_str2ad( at_row.cols[ 0 ], &ad, &text );
00395               if ( rc != LDAP_SUCCESS ) {
00396                      Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
00397                             "attribute \"%s\" for objectClass \"%s\" "
00398                             "is not defined in schema: %s\n", 
00399                             at_row.cols[ 0 ],
00400                             BACKSQL_OC_NAME( oc_map ), text );
00401                      bas->bas_rc = LDAP_CONSTRAINT_VIOLATION;
00402                      return BACKSQL_AVL_STOP;
00403               }
00404               at_map = (backsql_at_map_rec *)ch_calloc( 1,
00405                             sizeof( backsql_at_map_rec ) );
00406               at_map->bam_ad = ad;
00407               at_map->bam_true_ad = ad;
00408               if ( slap_syntax_is_binary( ad->ad_type->sat_syntax )
00409                      && !slap_ad_is_binary( ad ) )
00410               {
00411                      char          buf[ SLAP_TEXT_BUFLEN ];
00412                      struct berval bv;
00413                      const char    *text = NULL;
00414 
00415                      bv.bv_val = buf;
00416                      bv.bv_len = snprintf( buf, sizeof( buf ), "%s;binary",
00417                             ad->ad_cname.bv_val );
00418                      at_map->bam_true_ad = NULL;
00419                      bas->bas_rc = slap_bv2ad( &bv, &at_map->bam_true_ad, &text );
00420                      if ( bas->bas_rc != LDAP_SUCCESS ) {
00421                             Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
00422                                    "unable to fetch attribute \"%s\": %s (%d)\n",
00423                                    buf, text, rc );
00424                             return BACKSQL_AVL_STOP;
00425                      }
00426               }
00427 
00428               ber_str2bv( at_row.cols[ 1 ], 0, 1, &at_map->bam_sel_expr );
00429               if ( at_row.value_len[ 8 ] <= 0 ) {
00430                      BER_BVZERO( &at_map->bam_sel_expr_u );
00431 
00432               } else {
00433                      ber_str2bv( at_row.cols[ 8 ], 0, 1, 
00434                                    &at_map->bam_sel_expr_u );
00435               }
00436 
00437               ber_str2bv( at_row.cols[ 2 ], 0, 0, &bv );
00438               backsql_merge_from_clause( bas->bas_bi, &bb, &bv );
00439               at_map->bam_from_tbls = bb.bb_val;
00440               if ( at_row.value_len[ 3 ] <= 0 ) {
00441                      BER_BVZERO( &at_map->bam_join_where );
00442 
00443               } else {
00444                      ber_str2bv( at_row.cols[ 3 ], 0, 1, 
00445                                    &at_map->bam_join_where );
00446               }
00447               at_map->bam_add_proc = NULL;
00448               if ( at_row.value_len[ 4 ] > 0 ) {
00449                      at_map->bam_add_proc = ch_strdup( at_row.cols[ 4 ] );
00450               }
00451               at_map->bam_delete_proc = NULL;
00452               if ( at_row.value_len[ 5 ] > 0 ) {
00453                      at_map->bam_delete_proc = ch_strdup( at_row.cols[ 5 ] );
00454               }
00455               if ( lutil_atoix( &at_map->bam_param_order, at_row.cols[ 6 ], 0 ) != 0 ) {
00456                      /* error */
00457               }
00458               if ( lutil_atoix( &at_map->bam_expect_return, at_row.cols[ 7 ], 0 ) != 0 ) {
00459                      /* error */
00460               }
00461               backsql_make_attr_query( bas->bas_bi, oc_map, at_map );
00462               Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
00463                      "preconstructed query \"%s\"\n",
00464                      at_map->bam_query, 0, 0 );
00465               at_map->bam_next = NULL;
00466               if ( avl_insert( &oc_map->bom_attrs, at_map, backsql_cmp_attr, backsql_dup_attr ) == BACKSQL_DUPLICATE ) {
00467                      Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
00468                                    "duplicate attribute \"%s\" "
00469                                    "in objectClass \"%s\" map\n",
00470                                    at_map->bam_ad->ad_cname.bv_val,
00471                                    oc_map->bom_oc->soc_cname.bv_val, 0 );
00472               }
00473 
00474               if ( !BER_BVISNULL( &bas->bas_bi->sql_upper_func ) &&
00475                             BER_BVISNULL( &at_map->bam_sel_expr_u ) )
00476               {
00477                      struct berbuf bb = BB_NULL;
00478 
00479                      backsql_strfcat_x( &bb, NULL, "bcbc",
00480                                    &bas->bas_bi->sql_upper_func,
00481                                    '(' /* ) */ ,
00482                                    &at_map->bam_sel_expr,
00483                                    /* ( */ ')' );
00484                      at_map->bam_sel_expr_u = bb.bb_val;
00485               }
00486        }
00487        backsql_FreeRow( &at_row );
00488        SQLFreeStmt( bas->bas_sth, SQL_CLOSE );
00489 
00490        Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(\"%s\"): "
00491               "autoadding 'objectClass' and 'ref' mappings\n",
00492               BACKSQL_OC_NAME( oc_map ), 0, 0 );
00493 
00494        (void)backsql_add_sysmaps( bas->bas_bi, oc_map );
00495 
00496        return BACKSQL_AVL_CONTINUE;
00497 }
00498 
00499 
00500 int
00501 backsql_load_schema_map( backsql_info *bi, SQLHDBC dbh )
00502 {
00503        SQLHSTMT                    sth = SQL_NULL_HSTMT;
00504        RETCODE                            rc;
00505        BACKSQL_ROW_NTS                    oc_row;
00506        backsql_key_t               oc_id;
00507        backsql_oc_map_rec          *oc_map;
00508        struct backsql_attr_schema_info    bas;
00509 
00510        int                         delete_proc_idx = 5;
00511        int                         create_hint_idx = delete_proc_idx + 2;
00512 
00513        Debug( LDAP_DEBUG_TRACE, "==>backsql_load_schema_map()\n", 0, 0, 0 );
00514 
00515        /* 
00516         * TimesTen : See if the ldap_entries.dn_ru field exists in the schema
00517         */
00518        if ( !BACKSQL_DONTCHECK_LDAPINFO_DN_RU( bi ) ) {
00519               rc = backsql_Prepare( dbh, &sth, 
00520                             backsql_check_dn_ru_query, 0 );
00521               if ( rc == SQL_SUCCESS ) {
00522                      /* Yes, the field exists */
00523                      bi->sql_flags |= BSQLF_HAS_LDAPINFO_DN_RU;
00524                      Debug( LDAP_DEBUG_TRACE, "ldapinfo.dn_ru field exists "
00525                             "in the schema\n", 0, 0, 0 );
00526               } else {
00527                      /* No such field exists */
00528                      bi->sql_flags &= ~BSQLF_HAS_LDAPINFO_DN_RU;
00529               }
00530 
00531               SQLFreeStmt( sth, SQL_DROP );
00532        }
00533 
00534        Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): oc_query \"%s\"\n", 
00535                      bi->sql_oc_query, 0, 0 );
00536 
00537        rc = backsql_Prepare( dbh, &sth, bi->sql_oc_query, 0 );
00538        if ( rc != SQL_SUCCESS ) {
00539               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
00540                      "error preparing oc_query: \"%s\"\n", 
00541                      bi->sql_oc_query, 0, 0 );
00542               backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
00543               return LDAP_OTHER;
00544        }
00545 
00546        rc = SQLExecute( sth );
00547        if ( rc != SQL_SUCCESS ) {
00548               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
00549                      "error executing oc_query: \n", 0, 0, 0 );
00550               backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
00551               return LDAP_OTHER;
00552        }
00553 
00554        backsql_BindRowAsStrings( sth, &oc_row );
00555        rc = SQLFetch( sth );
00556 
00557        if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
00558               delete_proc_idx++;
00559               create_hint_idx++;
00560        }
00561 
00562        for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
00563               {
00564                      struct {
00565                             int idx;
00566                             char *name;
00567                      } required[] = {
00568                             { 0, "id" },
00569                             { 1, "name" },
00570                             { 2, "keytbl" },
00571                             { 3, "keycol" },
00572                             { -1, "expect_return" },
00573                             { -1, NULL },
00574                      };
00575                      int i;
00576 
00577                      required[4].idx = delete_proc_idx + 1;
00578 
00579                      for ( i = 0; required[ i ].name != NULL; i++ ) {
00580                             if ( oc_row.value_len[ required[ i ].idx ] <= 0 ) {
00581                                    Debug( LDAP_DEBUG_ANY,
00582                                           "backsql_load_schema_map(): "
00583                                           "required column #%d \"%s\" is empty\n",
00584                                           required[ i ].idx, required[ i ].name, 0 );
00585                                    return LDAP_OTHER;
00586                             }
00587                      }
00588               }
00589 
00590               {
00591                      char          buf[ SLAP_TEXT_BUFLEN ];
00592 
00593                      snprintf( buf, sizeof( buf ),
00594                             "objectClass: "
00595                             "id=\"%s\" "
00596                             "name=\"%s\" "
00597                             "keytbl=\"%s\" "
00598                             "keycol=\"%s\" "
00599                             "create_proc=\"%s\" "
00600                             "create_keyval=\"%s\" "
00601                             "delete_proc=\"%s\" "
00602                             "expect_return=\"%s\""
00603                             "create_hint=\"%s\" ",
00604                             oc_row.cols[ 0 ],
00605                             oc_row.cols[ 1 ],
00606                             oc_row.cols[ 2 ],
00607                             oc_row.cols[ 3 ],
00608                             oc_row.cols[ 4 ] ? oc_row.cols[ 4 ] : "",
00609                             ( BACKSQL_CREATE_NEEDS_SELECT( bi ) && oc_row.cols[ 5 ] ) ? oc_row.cols[ 5 ] : "",
00610                             oc_row.cols[ delete_proc_idx ] ? oc_row.cols[ delete_proc_idx ] : "",
00611                             oc_row.cols[ delete_proc_idx + 1 ],
00612                             ( ( oc_row.ncols > create_hint_idx ) && oc_row.cols[ create_hint_idx ] ) ? oc_row.cols[ create_hint_idx ] : "" );
00613                      Debug( LDAP_DEBUG_TRACE, "%s\n", buf, 0, 0 );
00614               }
00615 
00616               oc_map = (backsql_oc_map_rec *)ch_calloc( 1,
00617                             sizeof( backsql_oc_map_rec ) );
00618 
00619               if ( BACKSQL_STR2ID( &oc_map->bom_id, oc_row.cols[ 0 ], 0 ) != 0 ) {
00620                      Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
00621                             "unable to parse id=\"%s\"\n", 
00622                             oc_row.cols[ 0 ], 0, 0 );
00623                      return LDAP_OTHER;
00624               }
00625 
00626               oc_map->bom_oc = oc_find( oc_row.cols[ 1 ] );
00627               if ( oc_map->bom_oc == NULL ) {
00628                      Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
00629                             "objectClass \"%s\" is not defined in schema\n", 
00630                             oc_row.cols[ 1 ], 0, 0 );
00631                      return LDAP_OTHER;   /* undefined objectClass ? */
00632               }
00633               
00634               ber_str2bv( oc_row.cols[ 2 ], 0, 1, &oc_map->bom_keytbl );
00635               ber_str2bv( oc_row.cols[ 3 ], 0, 1, &oc_map->bom_keycol );
00636               oc_map->bom_create_proc = ( oc_row.value_len[ 4 ] <= 0 ) ? NULL 
00637                      : ch_strdup( oc_row.cols[ 4 ] );
00638 
00639               if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
00640                      oc_map->bom_create_keyval = ( oc_row.value_len[ 5 ] <= 0 ) 
00641                             ? NULL : ch_strdup( oc_row.cols[ 5 ] );
00642               }
00643               oc_map->bom_delete_proc = ( oc_row.value_len[ delete_proc_idx ] <= 0 ) ? NULL 
00644                      : ch_strdup( oc_row.cols[ delete_proc_idx ] );
00645               if ( lutil_atoix( &oc_map->bom_expect_return, oc_row.cols[ delete_proc_idx + 1 ], 0 ) != 0 ) {
00646                      Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
00647                             "unable to parse expect_return=\"%s\" for objectClass \"%s\"\n", 
00648                             oc_row.cols[ delete_proc_idx + 1 ], oc_row.cols[ 1 ], 0 );
00649                      return LDAP_OTHER;
00650               }
00651 
00652               if ( ( oc_row.ncols > create_hint_idx ) &&
00653                             ( oc_row.value_len[ create_hint_idx ] > 0 ) )
00654               {
00655                      const char    *text;
00656 
00657                      oc_map->bom_create_hint = NULL;
00658                      rc = slap_str2ad( oc_row.cols[ create_hint_idx ],
00659                                    &oc_map->bom_create_hint, &text );
00660                      if ( rc != SQL_SUCCESS ) {
00661                             Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
00662                                           "error matching "
00663                                           "AttributeDescription %s "
00664                                           "in create_hint: %s (%d)\n",
00665                                           oc_row.cols[ create_hint_idx ],
00666                                           text, rc );
00667                             backsql_PrintErrors( bi->sql_db_env, dbh,
00668                                           sth, rc );
00669                             return LDAP_OTHER;
00670                      }
00671               }
00672 
00673               /*
00674                * FIXME: first attempt to check for offending
00675                * instructions in {create|delete}_proc
00676                */
00677 
00678               oc_map->bom_attrs = NULL;
00679               if ( avl_insert( &bi->sql_oc_by_oc, oc_map, backsql_cmp_oc, avl_dup_error ) == -1 ) {
00680                      Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
00681                                    "duplicate objectClass \"%s\" in objectClass map\n",
00682                                    oc_map->bom_oc->soc_cname.bv_val, 0, 0 );
00683                      return LDAP_OTHER;
00684               }
00685               if ( avl_insert( &bi->sql_oc_by_id, oc_map, backsql_cmp_oc_id, avl_dup_error ) == -1 ) {
00686                      Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
00687                                    "duplicate objectClass \"%s\" in objectClass by ID map\n",
00688                                    oc_map->bom_oc->soc_cname.bv_val, 0, 0 );
00689                      return LDAP_OTHER;
00690               }
00691               oc_id = oc_map->bom_id;
00692               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
00693                      "objectClass \"%s\":\n    keytbl=\"%s\" keycol=\"%s\"\n",
00694                      BACKSQL_OC_NAME( oc_map ),
00695                      oc_map->bom_keytbl.bv_val, oc_map->bom_keycol.bv_val );
00696               if ( oc_map->bom_create_proc ) {
00697                      Debug( LDAP_DEBUG_TRACE, "    create_proc=\"%s\"\n",
00698                             oc_map->bom_create_proc, 0, 0 );
00699               }
00700               if ( oc_map->bom_create_keyval ) {
00701                      Debug( LDAP_DEBUG_TRACE, "    create_keyval=\"%s\"\n",
00702                             oc_map->bom_create_keyval, 0, 0 );
00703               }
00704               if ( oc_map->bom_create_hint ) {
00705                      Debug( LDAP_DEBUG_TRACE, "    create_hint=\"%s\"\n", 
00706                             oc_map->bom_create_hint->ad_cname.bv_val,
00707                             0, 0 );
00708               }
00709               if ( oc_map->bom_delete_proc ) {
00710                      Debug( LDAP_DEBUG_TRACE, "    delete_proc=\"%s\"\n", 
00711                             oc_map->bom_delete_proc, 0, 0 );
00712               }
00713               Debug( LDAP_DEBUG_TRACE, "    expect_return: "
00714                      "add=%d, del=%d; attributes:\n",
00715                      BACKSQL_IS_ADD( oc_map->bom_expect_return ), 
00716                      BACKSQL_IS_DEL( oc_map->bom_expect_return ), 0 );
00717        }
00718 
00719        backsql_FreeRow( &oc_row );
00720        SQLFreeStmt( sth, SQL_DROP );
00721 
00722        /* prepare for attribute fetching */
00723        Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): at_query \"%s\"\n", 
00724                      bi->sql_at_query, 0, 0 );
00725 
00726        rc = backsql_Prepare( dbh, &sth, bi->sql_at_query, 0 );
00727        if ( rc != SQL_SUCCESS ) {
00728               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
00729                      "error preparing at_query: \"%s\"\n", 
00730                      bi->sql_at_query, 0, 0 );
00731               backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
00732               return LDAP_OTHER;
00733        }
00734 
00735        rc = backsql_BindParamNumID( sth, 1, SQL_PARAM_INPUT, &oc_id );
00736        if ( rc != SQL_SUCCESS ) {
00737               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
00738                      "error binding param \"oc_id\" for at_query\n", 0, 0, 0 );
00739               backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
00740               SQLFreeStmt( sth, SQL_DROP );
00741               return LDAP_OTHER;
00742        }
00743 
00744        bas.bas_bi = bi;
00745        bas.bas_dbh = dbh;
00746        bas.bas_sth = sth;
00747        bas.bas_oc_id = &oc_id;
00748        bas.bas_rc = LDAP_SUCCESS;
00749 
00750        (void)avl_apply( bi->sql_oc_by_oc, backsql_oc_get_attr_mapping,
00751                      &bas, BACKSQL_AVL_STOP, AVL_INORDER );
00752 
00753        SQLFreeStmt( sth, SQL_DROP );
00754 
00755        bi->sql_flags |= BSQLF_SCHEMA_LOADED;
00756 
00757        Debug( LDAP_DEBUG_TRACE, "<==backsql_load_schema_map()\n", 0, 0, 0 );
00758 
00759        return bas.bas_rc;
00760 }
00761 
00762 backsql_oc_map_rec *
00763 backsql_oc2oc( backsql_info *bi, ObjectClass *oc )
00764 {
00765        backsql_oc_map_rec   tmp, *res;
00766 
00767 #ifdef BACKSQL_TRACE
00768        Debug( LDAP_DEBUG_TRACE, "==>backsql_oc2oc(): "
00769               "searching for objectclass with name=\"%s\"\n",
00770               oc->soc_cname.bv_val, 0, 0 );
00771 #endif /* BACKSQL_TRACE */
00772 
00773        tmp.bom_oc = oc;
00774        res = (backsql_oc_map_rec *)avl_find( bi->sql_oc_by_oc, &tmp, backsql_cmp_oc );
00775 #ifdef BACKSQL_TRACE
00776        if ( res != NULL ) {
00777               Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
00778                      "found name=\"%s\", id=%d\n", 
00779                      BACKSQL_OC_NAME( res ), res->bom_id, 0 );
00780        } else {
00781               Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
00782                      "not found\n", 0, 0, 0 );
00783        }
00784 #endif /* BACKSQL_TRACE */
00785  
00786        return res;
00787 }
00788 
00789 backsql_oc_map_rec *
00790 backsql_name2oc( backsql_info *bi, struct berval *oc_name )
00791 {
00792        backsql_oc_map_rec   tmp, *res;
00793 
00794 #ifdef BACKSQL_TRACE
00795        Debug( LDAP_DEBUG_TRACE, "==>oc_with_name(): "
00796               "searching for objectclass with name=\"%s\"\n",
00797               oc_name->bv_val, 0, 0 );
00798 #endif /* BACKSQL_TRACE */
00799 
00800        tmp.bom_oc = oc_bvfind( oc_name );
00801        if ( tmp.bom_oc == NULL ) {
00802               return NULL;
00803        }
00804 
00805        res = (backsql_oc_map_rec *)avl_find( bi->sql_oc_by_oc, &tmp, backsql_cmp_oc );
00806 #ifdef BACKSQL_TRACE
00807        if ( res != NULL ) {
00808               Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
00809                      "found name=\"%s\", id=%d\n", 
00810                      BACKSQL_OC_NAME( res ), res->bom_id, 0 );
00811        } else {
00812               Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
00813                      "not found\n", 0, 0, 0 );
00814        }
00815 #endif /* BACKSQL_TRACE */
00816  
00817        return res;
00818 }
00819 
00820 backsql_oc_map_rec *
00821 backsql_id2oc( backsql_info *bi, unsigned long id )
00822 {
00823        backsql_oc_map_rec   tmp, *res;
00824  
00825 #ifdef BACKSQL_TRACE
00826        Debug( LDAP_DEBUG_TRACE, "==>oc_with_id(): "
00827               "searching for objectclass with id=%lu\n", id, 0, 0 );
00828 #endif /* BACKSQL_TRACE */
00829 
00830        tmp.bom_id = id;
00831        res = (backsql_oc_map_rec *)avl_find( bi->sql_oc_by_id, &tmp,
00832                      backsql_cmp_oc_id );
00833 
00834 #ifdef BACKSQL_TRACE
00835        if ( res != NULL ) {
00836               Debug( LDAP_DEBUG_TRACE, "<==oc_with_id(): "
00837                      "found name=\"%s\", id=%lu\n",
00838                      BACKSQL_OC_NAME( res ), res->bom_id, 0 );
00839        } else {
00840               Debug( LDAP_DEBUG_TRACE, "<==oc_with_id(): "
00841                      "id=%lu not found\n", res->bom_id, 0, 0 );
00842        }
00843 #endif /* BACKSQL_TRACE */
00844        
00845        return res;
00846 }
00847 
00848 backsql_at_map_rec *
00849 backsql_ad2at( backsql_oc_map_rec* objclass, AttributeDescription *ad )
00850 {
00851        backsql_at_map_rec   tmp = { 0 }, *res;
00852  
00853 #ifdef BACKSQL_TRACE
00854        Debug( LDAP_DEBUG_TRACE, "==>backsql_ad2at(): "
00855               "searching for attribute \"%s\" for objectclass \"%s\"\n",
00856               ad->ad_cname.bv_val, BACKSQL_OC_NAME( objclass ), 0 );
00857 #endif /* BACKSQL_TRACE */
00858 
00859        tmp.bam_ad = ad;
00860        res = (backsql_at_map_rec *)avl_find( objclass->bom_attrs, &tmp,
00861                      backsql_cmp_attr );
00862 
00863 #ifdef BACKSQL_TRACE
00864        if ( res != NULL ) {
00865               Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
00866                      "found name=\"%s\", sel_expr=\"%s\"\n",
00867                      res->bam_ad->ad_cname.bv_val,
00868                      res->bam_sel_expr.bv_val, 0 );
00869        } else {
00870               Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
00871                      "not found\n", 0, 0, 0 );
00872        }
00873 #endif /* BACKSQL_TRACE */
00874 
00875        return res;
00876 }
00877 
00878 /* attributeType inheritance */
00879 struct supad2at_t {
00880        backsql_at_map_rec   **ret;
00881        AttributeDescription *ad;
00882        unsigned             n;
00883 };
00884 
00885 #define SUPAD2AT_STOP       (-1)
00886 
00887 static int
00888 supad2at_f( void *v_at, void *v_arg )
00889 {
00890        backsql_at_map_rec   *at = (backsql_at_map_rec *)v_at;
00891        struct supad2at_t    *va = (struct supad2at_t *)v_arg;
00892 
00893        if ( is_at_subtype( at->bam_ad->ad_type, va->ad->ad_type ) ) {
00894               backsql_at_map_rec   **ret = NULL;
00895               unsigned             i;
00896 
00897               /* if already listed, holler! (should never happen) */
00898               if ( va->ret ) {
00899                      for ( i = 0; i < va->n; i++ ) {
00900                             if ( va->ret[ i ]->bam_ad == at->bam_ad ) {
00901                                    break;
00902                             }
00903                      }
00904 
00905                      if ( i < va->n ) {
00906                             return 0;
00907                      }
00908               }
00909 
00910               ret = ch_realloc( va->ret,
00911                             sizeof( backsql_at_map_rec * ) * ( va->n + 2 ) );
00912               if ( ret == NULL ) {
00913                      ch_free( va->ret );
00914                      va->ret = NULL;
00915                      va->n = 0;
00916                      return SUPAD2AT_STOP;
00917               }
00918 
00919               ret[ va->n ] = at;
00920               va->n++;
00921               ret[ va->n ] = NULL;
00922               va->ret = ret;
00923        }
00924 
00925        return 0;
00926 }
00927 
00928 /*
00929  * stores in *pret a NULL terminated array of pointers
00930  * to backsql_at_map_rec whose attributeType is supad->ad_type 
00931  * or derived from it
00932  */
00933 int
00934 backsql_supad2at( backsql_oc_map_rec *objclass, AttributeDescription *supad,
00935               backsql_at_map_rec ***pret )
00936 {
00937        struct supad2at_t    va = { 0 };
00938        int                  rc;
00939 
00940        assert( objclass != NULL );
00941        assert( supad != NULL );
00942        assert( pret != NULL );
00943 
00944        *pret = NULL;
00945 
00946        va.ad = supad;
00947 
00948        rc = avl_apply( objclass->bom_attrs, supad2at_f, &va,
00949                      SUPAD2AT_STOP, AVL_INORDER );
00950        if ( rc == SUPAD2AT_STOP ) {
00951               return -1;
00952        }
00953 
00954        *pret = va.ret;
00955 
00956        return 0;
00957 }
00958 
00959 static void
00960 backsql_free_attr( void *v_at )
00961 {
00962        backsql_at_map_rec   *at = v_at;
00963        
00964        Debug( LDAP_DEBUG_TRACE, "==>free_attr(): \"%s\"\n", 
00965                      at->bam_ad->ad_cname.bv_val, 0, 0 );
00966        ch_free( at->bam_sel_expr.bv_val );
00967        if ( !BER_BVISNULL( &at->bam_from_tbls ) ) {
00968               ch_free( at->bam_from_tbls.bv_val );
00969        }
00970        if ( !BER_BVISNULL( &at->bam_join_where ) ) {
00971               ch_free( at->bam_join_where.bv_val );
00972        }
00973        if ( at->bam_add_proc != NULL ) {
00974               ch_free( at->bam_add_proc );
00975        }
00976        if ( at->bam_delete_proc != NULL ) {
00977               ch_free( at->bam_delete_proc );
00978        }
00979        if ( at->bam_query != NULL ) {
00980               ch_free( at->bam_query );
00981        }
00982 
00983 #ifdef BACKSQL_COUNTQUERY
00984        if ( at->bam_countquery != NULL ) {
00985               ch_free( at->bam_countquery );
00986        }
00987 #endif /* BACKSQL_COUNTQUERY */
00988 
00989        /* TimesTen */
00990        if ( !BER_BVISNULL( &at->bam_sel_expr_u ) ) {
00991               ch_free( at->bam_sel_expr_u.bv_val );
00992        }
00993 
00994        if ( at->bam_next ) {
00995               backsql_free_attr( at->bam_next );
00996        }
00997        
00998        ch_free( at );
00999 
01000        Debug( LDAP_DEBUG_TRACE, "<==free_attr()\n", 0, 0, 0 );
01001 }
01002 
01003 static void
01004 backsql_free_oc( void *v_oc )
01005 {
01006        backsql_oc_map_rec   *oc = v_oc;
01007        
01008        Debug( LDAP_DEBUG_TRACE, "==>free_oc(): \"%s\"\n", 
01009                      BACKSQL_OC_NAME( oc ), 0, 0 );
01010        avl_free( oc->bom_attrs, backsql_free_attr );
01011        ch_free( oc->bom_keytbl.bv_val );
01012        ch_free( oc->bom_keycol.bv_val );
01013        if ( oc->bom_create_proc != NULL ) {
01014               ch_free( oc->bom_create_proc );
01015        }
01016        if ( oc->bom_create_keyval != NULL ) {
01017               ch_free( oc->bom_create_keyval );
01018        }
01019        if ( oc->bom_delete_proc != NULL ) {
01020               ch_free( oc->bom_delete_proc );
01021        }
01022        ch_free( oc );
01023 
01024        Debug( LDAP_DEBUG_TRACE, "<==free_oc()\n", 0, 0, 0 );
01025 }
01026 
01027 int
01028 backsql_destroy_schema_map( backsql_info *bi )
01029 {
01030        Debug( LDAP_DEBUG_TRACE, "==>destroy_schema_map()\n", 0, 0, 0 );
01031        avl_free( bi->sql_oc_by_oc, 0 );
01032        avl_free( bi->sql_oc_by_id, backsql_free_oc );
01033        Debug( LDAP_DEBUG_TRACE, "<==destroy_schema_map()\n", 0, 0, 0 );
01034        return 0;
01035 }
01036