/* check entry's schema */
        rs->sr_err = entry_schema_check( op, op->oq_add.rs_e, NULL,
-               get_relax(op), 1, &rs->sr_text, textbuf, textlen );
+               get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
        if ( rs->sr_err != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE,
                        LDAP_XSTRING(bdb_add) ": entry failed schema check: "
 
        BER_BVNULL
 };
 
+static void
+bdb_modify_idxflags(
+       Operation *op,
+       AttributeDescription *desc,
+       int got_delete,
+       Attribute *newattrs,
+       Attribute *oldattrs )
+{
+       struct berval   ix_at;
+       AttrInfo        *ai;
+
+       /* check if modified attribute was indexed
+        * but not in case of NOOP... */
+       ai = bdb_index_mask( op->o_bd, desc, &ix_at );
+       if ( ai ) {
+               if ( got_delete ) {
+                       Attribute       *ap;
+                       struct berval   ix2;
+
+                       ap = attr_find( oldattrs, desc );
+                       if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL;
+
+                       /* Find all other attrs that index to same slot */
+                       for ( ap = newattrs; ap; ap = ap->a_next ) {
+                               ai = bdb_index_mask( op->o_bd, ap->a_desc, &ix2 );
+                               if ( ai && ix2.bv_val == ix_at.bv_val )
+                                       ap->a_flags |= SLAP_ATTR_IXADD;
+                       }
+
+               } else {
+                       Attribute       *ap;
+
+                       ap = attr_find( newattrs, desc );
+                       if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD;
+               }
+       }
+}
+
 int bdb_modify_internal(
        Operation *op,
        DB_TXN *tid,
        Attribute       *ap;
        int                     glue_attr_delete = 0;
        int                     got_delete;
-       AttrInfo *ai;
 
        Debug( LDAP_DEBUG_TRACE, "bdb_modify_internal: 0x%08lx: %s\n",
                e->e_id, e->e_dn, 0);
        }
 
        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
-               struct berval ix_at;
                mod = &ml->sml_mod;
                got_delete = 0;
 
 
                if ( glue_attr_delete ) e->e_ocflags = 0;
 
+
                /* check if modified attribute was indexed
                 * but not in case of NOOP... */
-               ai = bdb_index_mask( op->o_bd, mod->sm_desc, &ix_at );
-               if ( ai && !op->o_noop ) {
-                       if ( got_delete ) {
-                               struct berval ix2;
-
-                               ap = attr_find( save_attrs, mod->sm_desc );
-                               if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL;
-
-                               /* Find all other attrs that index to same slot */
-                               for ( ap = e->e_attrs; ap; ap=ap->a_next ) {
-                                       ai = bdb_index_mask( op->o_bd, ap->a_desc, &ix2 );
-                                       if ( ai && ix2.bv_val == ix_at.bv_val )
-                                               ap->a_flags |= SLAP_ATTR_IXADD;
-                               }
-                       } else {
-                               ap = attr_find( e->e_attrs, mod->sm_desc );
-                               if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD;
-                       }
+               if ( !op->o_noop ) {
+                       bdb_modify_idxflags( op, mod->sm_desc, got_delete, e->e_attrs, save_attrs );
                }
        }
 
        /* check that the entry still obeys the schema */
-       rc = entry_schema_check( op, e, save_attrs, get_relax(op), 0,
+       ap = NULL;
+       rc = entry_schema_check( op, e, save_attrs, get_relax(op), 0, &ap,
                text, textbuf, textlen );
        if ( rc != LDAP_SUCCESS || op->o_noop ) {
                attrs_free( e->e_attrs );
                return rc;
        }
 
+       /* structuralObjectClass modified! */
+       if ( ap ) {
+               assert( ap->a_desc == slap_schema.si_ad_structuralObjectClass );
+               if ( !op->o_noop ) {
+                       bdb_modify_idxflags( op, slap_schema.si_ad_structuralObjectClass,
+                               1, e->e_attrs, save_attrs );
+               }
+       }
+
        /* update the indices of the modified attributes */
 
        /* start with deleting the old index entries */
 
                        entry->e_ocflags = 0;
                }
                /* check that the entry still obeys the schema */
-               rc = entry_schema_check( op, entry, NULL, 0, 0,
+               rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
                          &rs->sr_text, textbuf, sizeof( textbuf ) );
        }
 
 
        Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
 
-       rc = entry_schema_check( op, e, NULL, 0, 1,
+       rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
                &rs->sr_text, textbuf, sizeof( textbuf ) );
        if ( rc != LDAP_SUCCESS )
                goto send_res;
 
                }
 
                /* check that the entry still obeys the schema */
-               rc = entry_schema_check( op, e, save_attrs, 0, 0,
+               rc = entry_schema_check( op, e, save_attrs, 0, 0, NULL,
                        &text, textbuf, sizeof( textbuf ) );
                if ( rc != LDAP_SUCCESS ) {
                        rs->sr_err = rc;
 
 
        /* check entry's schema */
        rs->sr_err = entry_schema_check( op, op->oq_add.rs_e, NULL,
-               get_relax(op), 1, &rs->sr_text, textbuf, textlen );
+               get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
        if ( rs->sr_err != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE,
                        LDAP_XSTRING(ndb_back_add) ": entry failed schema check: "
 
        }
 
        /* check that the entry still obeys the schema */
-       rc = entry_schema_check( op, NA->e, NULL, get_relax(op), 0,
+       rc = entry_schema_check( op, NA->e, NULL, get_relax(op), 0, NULL,
                text, textbuf, textlen );
        if ( rc != LDAP_SUCCESS || op->o_noop ) {
                if ( rc != LDAP_SUCCESS ) {
 
        if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
                char            textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
 
-               rs->sr_err = entry_schema_check( op, op->ora_e, NULL, 0, 1,
+               rs->sr_err = entry_schema_check( op, op->ora_e, NULL, 0, 1, NULL,
                        &rs->sr_text, textbuf, sizeof( textbuf ) );
                if ( rs->sr_err != LDAP_SUCCESS ) {
                        Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
 
                        goto do_transact;
                }
 
-               rs->sr_err = entry_schema_check( op, &m, NULL, 0, 0,
+               rs->sr_err = entry_schema_check( op, &m, NULL, 0, 0, NULL,
                        &rs->sr_text, textbuf, sizeof( textbuf ) );
                if ( rs->sr_err != LDAP_SUCCESS ) {
                        Debug( LDAP_DEBUG_TRACE, "   backsql_modify(\"%s\"): "
 
 
                e_id = bsi.bsi_base_id;
 
-               rs->sr_err = entry_schema_check( op, &r, NULL, 0, 0,
+               rs->sr_err = entry_schema_check( op, &r, NULL, 0, 0, NULL,
                        &rs->sr_text, textbuf, sizeof( textbuf ) );
                if ( rs->sr_err != LDAP_SUCCESS ) {
                        Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(\"%s\"): "
 
        {
                char textbuf[SLAP_TEXT_BUFLEN];
                size_t textlen = sizeof textbuf;
-               rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1,
+               rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1, NULL,
                        &rs->sr_text, textbuf, sizeof( textbuf ) );
                if ( rs->sr_err != LDAP_SUCCESS )
                        goto out;
        
        if ( rc == LDAP_SUCCESS) {
                /* check that the entry still obeys the schema */
-               rc = entry_schema_check(op, e, NULL, 0, 0,
+               rc = entry_schema_check(op, e, NULL, 0, 0, NULL,
                        &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) );
        }
        if ( rc ) goto out_noop;
 
        Attribute *attrs,
        int manage,
        int add,
+       Attribute **socp,
        const char** text,
        char *textbuf, size_t textlen );
 
 
        Attribute *oldattrs,
        int manage,
        int add,
+       Attribute **socp,
        const char** text,
        char *textbuf, size_t textlen )
 {
                rc = LDAP_OBJECT_CLASS_VIOLATION;
                goto done;
 
-       } else if ( sc != slap_schema.si_oc_glue && sc != oc ) {
-               snprintf( textbuf, textlen, 
-                       "structural object class modification "
-                       "from '%s' to '%s' not allowed",
-                       asc->a_vals[0].bv_val, oc->soc_cname.bv_val );
-               rc = LDAP_NO_OBJECT_CLASS_MODS;
-               goto done;
-       } else if ( sc == slap_schema.si_oc_glue ) {
+       } else if ( sc != oc ) {
+               if ( !manage && sc != slap_schema.si_oc_glue ) {
+                       snprintf( textbuf, textlen, 
+                               "structural object class modification "
+                               "from '%s' to '%s' not allowed",
+                               asc->a_vals[0].bv_val, oc->soc_cname.bv_val );
+                       rc = LDAP_NO_OBJECT_CLASS_MODS;
+                       goto done;
+               }
+
+               assert( asc->a_vals != NULL );
+               assert( !BER_BVISNULL( &asc->a_vals[0] ) );
+               assert( BER_BVISNULL( &asc->a_vals[1] ) );
+               assert( asc->a_nvals == asc->a_vals );
+
+               /* draft-zeilenga-ldap-relax: automatically modify
+                * structuralObjectClass if changed with relax */
                sc = oc;
+               ber_bvreplace( &asc->a_vals[ 0 ], &sc->soc_cname );
+               if ( socp ) {
+                       *socp = asc;
+               }
        }
 
        /* naming check */
 
                        op->o_bd = be;
 
                        if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) {
-                               rc = entry_schema_check( op, e, NULL, manage, 1,
+                               rc = entry_schema_check( op, e, NULL, manage, 1, NULL,
                                        &text, textbuf, textlen );
 
                                if( rc != LDAP_SUCCESS ) {
 
 
        pb->pb_op->o_bd = select_backend( &e->e_nname, 0 );
        if ( pb->pb_op->o_bd != NULL ) {
-               rc = entry_schema_check( pb->pb_op, e, NULL, 0, 0,
+               rc = entry_schema_check( pb->pb_op, e, NULL, 0, 0, NULL,
                        &text, textbuf, textlen );
        }
        pb->pb_op->o_bd = be_orig;