]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-sql/entry-id.c
ITS#5892 return -1 from ldif_read_record on error
[openldap] / servers / slapd / back-sql / entry-id.c
index 35f793cde2ac9bd10d55c96bc0e2d97cd8b33964..e1351b996728e409c3ebb679c34a7a3844c2fb2e 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1999-2005 The OpenLDAP Foundation.
+ * Copyright 1999-2009 The OpenLDAP Foundation.
  * Portions Copyright 1999 Dmitry Kovalev.
  * Portions Copyright 2002 Pierangelo Masarati.
  * Portions Copyright 2004 Mark Adamson.
@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include "ac/string.h"
 
+#include "lutil.h"
 #include "slap.h"
 #include "proto-sql.h"
 
@@ -35,7 +36,36 @@ struct berval backsql_baseObject_bv = BER_BVC( BACKSQL_BASEOBJECT_IDSTR );
 #endif /* BACKSQL_ARBITRARY_KEY */
 
 backsql_entryID *
-backsql_free_entryID( Operation *op, backsql_entryID *id, int freeit )
+backsql_entryID_dup( backsql_entryID *src, void *ctx )
+{
+       backsql_entryID *dst;
+
+       if ( src == NULL ) return NULL;
+
+       dst = slap_sl_calloc( 1, sizeof( backsql_entryID ), ctx );
+       ber_dupbv_x( &dst->eid_ndn, &src->eid_ndn, ctx );
+       if ( src->eid_dn.bv_val == src->eid_ndn.bv_val ) {
+               dst->eid_dn = dst->eid_ndn;
+       } else {
+               ber_dupbv_x( &dst->eid_dn, &src->eid_dn, ctx );
+       }
+
+#ifdef BACKSQL_ARBITRARY_KEY
+       ber_dupbv_x( &dst->eid_id, &src->eid_id, ctx );
+       ber_dupbv_x( &dst->eid_keyval, &src->eid_keyval, ctx );
+#else /* ! BACKSQL_ARBITRARY_KEY */
+       dst->eid_id = src->eid_id;
+       dst->eid_keyval = src->eid_keyval;
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+
+       dst->eid_oc = src->eid_oc;
+       dst->eid_oc_id = src->eid_oc_id;
+
+       return dst;
+}
+
+backsql_entryID *
+backsql_free_entryID( backsql_entryID *id, int freeit, void *ctx )
 {
        backsql_entryID         *next;
 
@@ -47,28 +77,28 @@ backsql_free_entryID( Operation *op, backsql_entryID *id, int freeit )
                if ( !BER_BVISNULL( &id->eid_dn )
                                && id->eid_dn.bv_val != id->eid_ndn.bv_val )
                {
-                       op->o_tmpfree( id->eid_dn.bv_val, op->o_tmpmemctx );
+                       slap_sl_free( id->eid_dn.bv_val, ctx );
                        BER_BVZERO( &id->eid_dn );
                }
 
-               op->o_tmpfree( id->eid_ndn.bv_val, op->o_tmpmemctx );
+               slap_sl_free( id->eid_ndn.bv_val, ctx );
                BER_BVZERO( &id->eid_ndn );
        }
 
 #ifdef BACKSQL_ARBITRARY_KEY
        if ( !BER_BVISNULL( &id->eid_id ) ) {
-               op->o_tmpfree( id->eid_id.bv_val, op->o_tmpmemctx );
+               slap_sl_free( id->eid_id.bv_val, ctx );
                BER_BVZERO( &id->eid_id );
        }
 
        if ( !BER_BVISNULL( &id->eid_keyval ) ) {
-               op->o_tmpfree( id->eid_keyval.bv_val, op->o_tmpmemctx );
+               slap_sl_free( id->eid_keyval.bv_val, ctx );
                BER_BVZERO( &id->eid_keyval );
        }
 #endif /* BACKSQL_ARBITRARY_KEY */
 
        if ( freeit ) {
-               op->o_tmpfree( id, op->o_tmpmemctx );
+               slap_sl_free( id, ctx );
        }
 
        return next;
@@ -89,7 +119,7 @@ backsql_dn2id(
 {
        backsql_info            *bi = op->o_bd->be_private;
        SQLHSTMT                sth = SQL_NULL_HSTMT; 
-       BACKSQL_ROW_NTS         row;
+       BACKSQL_ROW_NTS         row = { 0 };
        RETCODE                 rc;
        int                     res;
        struct berval           realndn = BER_BVNULL;
@@ -231,7 +261,7 @@ backsql_dn2id(
                goto done;
        }
 
-       backsql_BindRowAsStrings( sth, &row );
+       backsql_BindRowAsStrings_x( sth, &row, op->o_tmpmemctx );
        rc = SQLFetch( sth );
        if ( BACKSQL_SUCCESS( rc ) ) {
                char    buf[ SLAP_TEXT_BUFLEN ];
@@ -250,43 +280,52 @@ backsql_dn2id(
                if ( id != NULL ) {
                        struct berval   dn;
 
+                       id->eid_next = NULL;
+
 #ifdef BACKSQL_ARBITRARY_KEY
                        ber_str2bv_x( row.cols[ 0 ], 0, 1, &id->eid_id,
                                        op->o_tmpmemctx );
                        ber_str2bv_x( row.cols[ 1 ], 0, 1, &id->eid_keyval,
                                        op->o_tmpmemctx );
 #else /* ! BACKSQL_ARBITRARY_KEY */
-                       id->eid_id = strtol( row.cols[ 0 ], NULL, 0 );
-                       id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 );
+                       if ( lutil_atoulx( &id->eid_id, row.cols[ 0 ], 0 ) != 0 ) {
+                               res = LDAP_OTHER;
+                               goto done;
+                       }
+                       if ( lutil_atoulx( &id->eid_keyval, row.cols[ 1 ], 0 ) != 0 ) {
+                               res = LDAP_OTHER;
+                               goto done;
+                       }
 #endif /* ! BACKSQL_ARBITRARY_KEY */
-                       id->eid_oc_id = strtol( row.cols[ 2 ], NULL, 0 );
+                       if ( lutil_atoulx( &id->eid_oc_id, row.cols[ 2 ], 0 ) != 0 ) {
+                               res = LDAP_OTHER;
+                               goto done;
+                       }
 
                        ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
 
                        if ( backsql_api_odbc2dn( op, rs, &dn ) ) {
                                res = LDAP_OTHER;
-
-                       } else {
-                               res = dnPrettyNormal( NULL, &dn,
-                                               &id->eid_dn, &id->eid_ndn,
-                                               op->o_tmpmemctx );
-                               if ( res != LDAP_SUCCESS ) {
-                                       Debug( LDAP_DEBUG_TRACE,
-                                               "   backsql_dn2id(\"%s\"): "
-                                               "dnPrettyNormal failed (%d: %s)\n",
-                                               realndn.bv_val, res,
-                                               ldap_err2string( res ) );
-
-                                       /* cleanup... */
-                                       (void)backsql_free_entryID( op, id, 0 );
-                               }
-
-                               if ( dn.bv_val != row.cols[ 3 ] ) {
-                                       free( dn.bv_val );
-                               }
+                               goto done;
+                       }
+                       
+                       res = dnPrettyNormal( NULL, &dn,
+                                       &id->eid_dn, &id->eid_ndn,
+                                       op->o_tmpmemctx );
+                       if ( res != LDAP_SUCCESS ) {
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "   backsql_dn2id(\"%s\"): "
+                                       "dnPrettyNormal failed (%d: %s)\n",
+                                       realndn.bv_val, res,
+                                       ldap_err2string( res ) );
+
+                               /* cleanup... */
+                               (void)backsql_free_entryID( id, 0, op->o_tmpmemctx );
                        }
 
-                       id->eid_next = NULL;
+                       if ( dn.bv_val != row.cols[ 3 ] ) {
+                               free( dn.bv_val );
+                       }
                }
 
        } else {
@@ -324,9 +363,10 @@ backsql_dn2id(
                        }
                }
        }
-       backsql_FreeRow( &row );
 
 done:;
+       backsql_FreeRow_x( &row, op->o_tmpmemctx );
+
        Debug( LDAP_DEBUG_TRACE,
                "<==backsql_dn2id(\"%s\"): err=%d\n",
                ndn->bv_val, res, 0 );
@@ -343,11 +383,12 @@ done:;
 
 int
 backsql_count_children(
-       backsql_info            *bi,
+       Operation               *op,
        SQLHDBC                 dbh,
        struct berval           *dn,
        unsigned long           *nchildren )
 {
+       backsql_info            *bi = (backsql_info *)op->o_bd->be_private;
        SQLHSTMT                sth = SQL_NULL_HSTMT;
        BACKSQL_ROW_NTS         row;
        RETCODE                 rc;
@@ -399,24 +440,41 @@ backsql_count_children(
                return LDAP_OTHER;
        }
 
-       backsql_BindRowAsStrings( sth, &row );
+       backsql_BindRowAsStrings_x( sth, &row, op->o_tmpmemctx );
        
        rc = SQLFetch( sth );
        if ( BACKSQL_SUCCESS( rc ) ) {
                char *end;
 
                *nchildren = strtol( row.cols[ 0 ], &end, 0 );
-               if ( end[ 0 ] != '\0' && end[0] != '.' ) {
-                       /* FIXME: braindead RDBMSes return
-                        * a fractional number from COUNT!
-                        */
+               if ( end == row.cols[ 0 ] ) {
                        res = LDAP_OTHER;
+
+               } else {
+                       switch ( end[ 0 ] ) {
+                       case '\0':
+                               break;
+
+                       case '.': {
+                               unsigned long   ul;
+
+                               /* FIXME: braindead RDBMSes return
+                                * a fractional number from COUNT!
+                                */
+                               if ( lutil_atoul( &ul, end + 1 ) != 0 || ul != 0 ) {
+                                       res = LDAP_OTHER;
+                               }
+                               } break;
+
+                       default:
+                               res = LDAP_OTHER;
+                       }
                }
 
        } else {
                res = LDAP_OTHER;
        }
-       backsql_FreeRow( &row );
+       backsql_FreeRow_x( &row, op->o_tmpmemctx );
 
        SQLFreeStmt( sth, SQL_DROP );
 
@@ -428,14 +486,14 @@ backsql_count_children(
 
 int
 backsql_has_children(
-       backsql_info            *bi,
+       Operation               *op,
        SQLHDBC                 dbh,
        struct berval           *dn )
 {
        unsigned long   nchildren;
        int             rc;
 
-       rc = backsql_count_children( bi, dbh, dn, &nchildren );
+       rc = backsql_count_children( op, dbh, dn, &nchildren );
 
        if ( rc == LDAP_SUCCESS ) {
                return nchildren > 0 ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
@@ -455,12 +513,13 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
        BACKSQL_ROW_NTS         row;
        unsigned long           i,
                                k = 0,
-                               oldcount = 0;
+                               oldcount = 0,
+                               res = 0;
 #ifdef BACKSQL_COUNTQUERY
-       unsigned long           count,
-                               countsize = sizeof( count ),
+       unsigned                count,
                                j,
                                append = 0;
+       SQLLEN                  countsize = sizeof( count );
        Attribute               *attr = NULL;
 
        slap_mr_normalize_func          *normfunc = NULL;
@@ -486,8 +545,8 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
 #endif /* ! BACKSQL_ARBITRARY_KEY */
 
 #ifdef BACKSQL_PRETTY_VALIDATE
-       validate = at->bam_ad->ad_type->sat_syntax->ssyn_validate;
-       pretty =  at->bam_ad->ad_type->sat_syntax->ssyn_pretty;
+       validate = at->bam_true_ad->ad_type->sat_syntax->ssyn_validate;
+       pretty =  at->bam_true_ad->ad_type->sat_syntax->ssyn_pretty;
 
        if ( validate == NULL && pretty == NULL ) {
                return 1;
@@ -495,8 +554,8 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
 #endif /* BACKSQL_PRETTY_VALIDATE */
 
 #ifdef BACKSQL_COUNTQUERY
-       if ( at->bam_ad->ad_type->sat_equality ) {
-               normfunc = at->bam_ad->ad_type->sat_equality->smr_normalize;
+       if ( at->bam_true_ad->ad_type->sat_equality ) {
+               normfunc = at->bam_true_ad->ad_type->sat_equality->smr_normalize;
        }
 
        /* Count how many rows will be returned. This avoids memory 
@@ -547,19 +606,18 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
        }
 
        Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
-               "number of values in query: %d\n", count, 0, 0 );
+               "number of values in query: %u\n", count, 0, 0 );
        SQLFreeStmt( sth, SQL_DROP );
        if ( count == 0 ) {
                return 1;
        }
 
-       attr = attr_find( bsi->bsi_e->e_attrs, at->bam_ad );
+       attr = attr_find( bsi->bsi_e->e_attrs, at->bam_true_ad );
        if ( attr != NULL ) {
                BerVarray       tmp;
 
                if ( attr->a_vals != NULL ) {
-                       for ( ; !BER_BVISNULL( &attr->a_vals[ oldcount ] ); oldcount++ )
-                               /* just count */ ;
+                       oldcount = attr->a_numvals;
                }
 
                tmp = ch_realloc( attr->a_vals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
@@ -580,22 +638,20 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                } else {
                        attr->a_nvals = attr->a_vals;
                }
+               attr->a_numvals += count;
 
        } else {
                append = 1;
 
                /* Make space for the array of values */
-               attr = (Attribute *) ch_malloc( sizeof( Attribute ) );
-               attr->a_desc = at->bam_ad;
-               attr->a_flags = 0;
-               attr->a_next = NULL;
+               attr = attr_alloc( at->bam_true_ad );
+               attr->a_numvals = count;
                attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) );
                if ( attr->a_vals == NULL ) {
                        Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 );
                        ch_free( attr );
                        return 1;
                }
-               memset( attr->a_vals, 0, ( count + 1 ) * sizeof( struct berval ) );
                if ( normfunc ) {
                        attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) );
                        if ( attr->a_nvals == NULL ) {
@@ -603,8 +659,6 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                                ch_free( attr );
                                return 1;
 
-                       } else {
-                               memset( attr->a_nvals, 0, ( count + 1 ) * sizeof( struct berval ) );
                        }
 
                } else {
@@ -618,6 +672,11 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
                        "error preparing query: %s\n", at->bam_query, 0, 0 );
                backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
+#ifdef BACKSQL_COUNTQUERY
+               if ( append ) {
+                       attr_free( attr );
+               }
+#endif /* BACKSQL_COUNTQUERY */
                return 1;
        }
 
@@ -626,6 +685,11 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
        if ( rc != SQL_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
                        "error binding key value parameter\n", 0, 0, 0 );
+#ifdef BACKSQL_COUNTQUERY
+               if ( append ) {
+                       attr_free( attr );
+               }
+#endif /* BACKSQL_COUNTQUERY */
                return 1;
        }
 
@@ -648,10 +712,15 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                        at->bam_query, 0, 0 );
                backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
                SQLFreeStmt( sth, SQL_DROP );
+#ifdef BACKSQL_COUNTQUERY
+               if ( append ) {
+                       attr_free( attr );
+               }
+#endif /* BACKSQL_COUNTQUERY */
                return 1;
        }
 
-       backsql_BindRowAsStrings( sth, &row );
+       backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx );
 #ifdef BACKSQL_COUNTQUERY
        j = oldcount;
 #endif /* BACKSQL_COUNTQUERY */
@@ -659,7 +728,7 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                        BACKSQL_SUCCESS( rc );
                        rc = SQLFetch( sth ), k++ )
        {
-               for ( i = 0; i < row.ncols; i++ ) {
+               for ( i = 0; i < (unsigned long)row.ncols; i++ ) {
 
                        if ( row.value_len[ i ] > 0 ) {
                                struct berval           bv;
@@ -676,7 +745,8 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                                                "in schema (%d)\n",
                                                bsi->bsi_e->e_name.bv_val,
                                                row.col_names[ i ].bv_val, retval );
-                                       return 1;
+                                       res = 1;
+                                       goto done;
                                }
 
                                if ( ad != at->bam_ad ) {
@@ -687,26 +757,43 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                                                bsi->bsi_e->e_name.bv_val,
                                                ad->ad_cname.bv_val,
                                                at->bam_ad->ad_cname.bv_val );
-                                       return 1;
+                                       res = 1;
+                                       goto done;
                                }
 #endif /* BACKSQL_TRACE */
 
-                               /*
-                                * FIXME: what if a binary 
-                                * is fetched?
+                               /* ITS#3386, ITS#3113 - 20070308
+                                * If a binary is fetched?
+                                * must use the actual size read
+                                * from the database.
                                 */
-                               ber_str2bv( row.cols[ i ], 0, 0, &bv );
+                               if ( BACKSQL_IS_BINARY( row.col_type[ i ] ) ) {
+#ifdef BACKSQL_TRACE
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "==>backsql_get_attr_vals(\"%s\"): "
+                                               "column name %s: data is binary; "
+                                               "using database size %ld\n",
+                                               bsi->bsi_e->e_name.bv_val,
+                                               ad->ad_cname.bv_val,
+                                               row.value_len[ i ] );
+#endif /* BACKSQL_TRACE */
+                                       bv.bv_val = row.cols[ i ];
+                                       bv.bv_len = row.value_len[ i ];
+
+                               } else {
+                                       ber_str2bv( row.cols[ i ], 0, 0, &bv );
+                               }
 
 #ifdef BACKSQL_PRETTY_VALIDATE
                                if ( pretty ) {
                                        struct berval   pbv;
 
-                                       retval = pretty( at->bam_ad->ad_type->sat_syntax,
+                                       retval = pretty( at->bam_true_ad->ad_type->sat_syntax,
                                                &bv, &pbv, bsi->bsi_op->o_tmpmemctx );
                                        bv = pbv;
 
                                } else {
-                                       retval = validate( at->bam_ad->ad_type->sat_syntax,
+                                       retval = validate( at->bam_true_ad->ad_type->sat_syntax,
                                                &bv );
                                }
 
@@ -717,11 +804,11 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                                         * but we're accepting the attributes;
                                         * should we fail at all? */
                                        snprintf( buf, sizeof( buf ),
-                                                       "unable to %s value #%d "
+                                                       "unable to %s value #%lu "
                                                        "of AttributeDescription %s",
                                                        pretty ? "prettify" : "validate",
-                                                       at->bam_ad->ad_cname.bv_val,
-                                                       k - oldcount );
+                                                       k - oldcount,
+                                                       at->bam_ad->ad_cname.bv_val );
                                        Debug( LDAP_DEBUG_TRACE,
                                                "==>backsql_get_attr_vals(\"%s\"): "
                                                "%s (%d)\n",
@@ -732,7 +819,7 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
 
 #ifndef BACKSQL_COUNTQUERY
                                (void)backsql_entry_addattr( bsi->bsi_e, 
-                                               at->bam_ad, &bv,
+                                               at->bam_true_ad, &bv,
                                                bsi->bsi_op->o_tmpmemctx );
 
 #else /* BACKSQL_COUNTQUERY */
@@ -740,8 +827,8 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                                        struct berval   nbv;
 
                                        retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
-                                               at->bam_ad->ad_type->sat_syntax,
-                                               at->bam_ad->ad_type->sat_equality,
+                                               at->bam_true_ad->ad_type->sat_syntax,
+                                               at->bam_true_ad->ad_type->sat_equality,
                                                &bv, &nbv,
                                                bsi->bsi_op->o_tmpmemctx );
 
@@ -752,10 +839,10 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                                                 * but we're accepting the attributes;
                                                 * should we fail at all? */
                                                snprintf( buf, sizeof( buf ),
-                                                       "unable to normalize value #%d "
+                                                       "unable to normalize value #%lu "
                                                        "of AttributeDescription %s",
-                                                       at->bam_ad->ad_cname.bv_val,
-                                                       k - oldcount );
+                                                       k - oldcount,
+                                                       at->bam_ad->ad_cname.bv_val );
                                                Debug( LDAP_DEBUG_TRACE,
                                                        "==>backsql_get_attr_vals(\"%s\"): "
                                                        "%s (%d)\n",
@@ -815,15 +902,21 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
        }
 #endif /* BACKSQL_COUNTQUERY */
 
-       backsql_FreeRow( &row );
        SQLFreeStmt( sth, SQL_DROP );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_get_attr_vals()\n", 0, 0, 0 );
 
        if ( at->bam_next ) {
-               return backsql_get_attr_vals( at->bam_next, v_bsi );
+               res = backsql_get_attr_vals( at->bam_next, v_bsi );
+       } else {
+               res = 1;
        }
 
-       return 1;
+#ifdef BACKSQL_TRACE
+done:;
+#endif /* BACKSQL_TRACE */
+       backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx );
+
+       return res;
 }
 
 int
@@ -859,8 +952,11 @@ backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid )
        bsi->bsi_e->e_attrs = NULL;
        bsi->bsi_e->e_private = NULL;
 
-       bsi->bsi_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private,
+       if ( eid->eid_oc == NULL ) {
+               eid->eid_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private,
                        eid->eid_oc_id );
+       }
+       bsi->bsi_oc = eid->eid_oc;
        bsi->bsi_c_eid = eid;
 
 #ifndef BACKSQL_ARBITRARY_KEY  
@@ -946,16 +1042,17 @@ next:;
        }
 
        if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER )
-                       || an_find( bsi->bsi_attrs, &AllOper )
+                       || an_find( bsi->bsi_attrs, slap_bv_all_operational_attrs )
                        || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) )
        {
+               ObjectClass     *soc = NULL;
+
                if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
                        Attribute       *a;
                        const char      *text = NULL;
                        char            textbuf[ 1024 ];
                        size_t          textlen = sizeof( textbuf );
-                       struct berval   soc,
-                                       bv[ 2 ],
+                       struct berval   bv[ 2 ],
                                        *nvals;
                        int             rc = LDAP_SUCCESS;
 
@@ -971,7 +1068,7 @@ next:;
                        }
 
                        rc = structural_class( nvals, &soc, NULL, 
-                                       &text, textbuf, textlen );
+                                       &text, textbuf, textlen, op->o_tmpmemctx );
                        if ( rc != LDAP_SUCCESS ) {
                                Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
                                        "structural_class() failed %d (%s)\n",
@@ -981,21 +1078,33 @@ next:;
                                return rc;
                        }
 
-                       if ( !bvmatch( &soc, &bsi->bsi_oc->bom_oc->soc_cname ) ) {
+                       if ( !bvmatch( &soc->soc_cname, &bsi->bsi_oc->bom_oc->soc_cname ) ) {
+                               if ( !is_object_subclass( bsi->bsi_oc->bom_oc, soc ) ) {
+                                       Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
+                                               "computed structuralObjectClass %s "
+                                               "does not match objectClass %s associated "
+                                               "to entry\n",
+                                               bsi->bsi_e->e_name.bv_val, soc->soc_cname.bv_val,
+                                               bsi->bsi_oc->bom_oc->soc_cname.bv_val );
+                                       backsql_entry_clean( op, bsi->bsi_e );
+                                       return rc;
+                               }
+
                                Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
                                        "computed structuralObjectClass %s "
-                                       "does not match objectClass %s associated "
+                                       "is subclass of objectClass %s associated "
                                        "to entry\n",
-                                       bsi->bsi_e->e_name.bv_val, soc.bv_val,
+                                       bsi->bsi_e->e_name.bv_val, soc->soc_cname.bv_val,
                                        bsi->bsi_oc->bom_oc->soc_cname.bv_val );
-                               backsql_entry_clean( op, bsi->bsi_e );
-                               return rc;
                        }
+
+               } else {
+                       soc = bsi->bsi_oc->bom_oc;
                }
 
                rc = attr_merge_normalize_one( bsi->bsi_e,
                                slap_schema.si_ad_structuralObjectClass,
-                               &bsi->bsi_oc->bom_oc->soc_cname,
+                               &soc->soc_cname,
                                bsi->bsi_op->o_tmpmemctx );
                if ( rc != LDAP_SUCCESS ) {
                        backsql_entry_clean( op, bsi->bsi_e );