X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-sql%2Fentry-id.c;h=e1351b996728e409c3ebb679c34a7a3844c2fb2e;hb=72e319bd02256465a0e8c8a2bc304ec11de97378;hp=96c27be1f44e2b0688afa5aa2855658b8d4cad44;hpb=4b0a9be3b58efe6af420b5540669251e085acc44;p=openldap diff --git a/servers/slapd/back-sql/entry-id.c b/servers/slapd/back-sql/entry-id.c index 96c27be1f4..e1351b9967 100644 --- a/servers/slapd/back-sql/entry-id.c +++ b/servers/slapd/back-sql/entry-id.c @@ -1,8 +1,9 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1999-2004 The OpenLDAP Foundation. + * Copyright 1999-2009 The OpenLDAP Foundation. * Portions Copyright 1999 Dmitry Kovalev. + * Portions Copyright 2002 Pierangelo Masarati. * Portions Copyright 2004 Mark Adamson. * All rights reserved. * @@ -16,7 +17,8 @@ */ /* ACKNOWLEDGEMENTS: * This work was initially developed by Dmitry Kovalev for inclusion - * by OpenLDAP Software. + * by OpenLDAP Software. Additional significant contributors include + * Pierangelo Masarati and Mark Adamson. */ #include "portable.h" @@ -25,6 +27,7 @@ #include #include "ac/string.h" +#include "lutil.h" #include "slap.h" #include "proto-sql.h" @@ -33,11 +36,40 @@ struct berval backsql_baseObject_bv = BER_BVC( BACKSQL_BASEOBJECT_IDSTR ); #endif /* BACKSQL_ARBITRARY_KEY */ backsql_entryID * -backsql_free_entryID( 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; - assert( id ); + assert( id != NULL ); next = id->eid_next; @@ -45,28 +77,28 @@ backsql_free_entryID( backsql_entryID *id, int freeit ) if ( !BER_BVISNULL( &id->eid_dn ) && id->eid_dn.bv_val != id->eid_ndn.bv_val ) { - free( id->eid_dn.bv_val ); + slap_sl_free( id->eid_dn.bv_val, ctx ); BER_BVZERO( &id->eid_dn ); } - free( id->eid_ndn.bv_val ); + slap_sl_free( id->eid_ndn.bv_val, ctx ); BER_BVZERO( &id->eid_ndn ); } #ifdef BACKSQL_ARBITRARY_KEY - if ( id->eid_id.bv_val ) { - free( id->eid_id.bv_val ); + if ( !BER_BVISNULL( &id->eid_id ) ) { + slap_sl_free( id->eid_id.bv_val, ctx ); BER_BVZERO( &id->eid_id ); } - if ( id->eid_keyval.bv_val ) { - free( id->eid_keyval.bv_val ); + if ( !BER_BVISNULL( &id->eid_keyval ) ) { + slap_sl_free( id->eid_keyval.bv_val, ctx ); BER_BVZERO( &id->eid_keyval ); } #endif /* BACKSQL_ARBITRARY_KEY */ if ( freeit ) { - free( id ); + slap_sl_free( id, ctx ); } return next; @@ -79,14 +111,15 @@ int backsql_dn2id( Operation *op, SlapReply *rs, - backsql_entryID *id, SQLHDBC dbh, struct berval *ndn, + backsql_entryID *id, + int matched, int muck ) { 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; @@ -103,13 +136,19 @@ backsql_dn2id( * positive cases, or the most appropriate error */ - Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(): dn=\"%s\"%s\n", - ndn->bv_val, id == NULL ? " (no ID)" : "", 0 ); + Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(\"%s\")%s%s\n", + ndn->bv_val, id == NULL ? " (no ID expected)" : "", + matched ? " matched expected" : "" ); + + if ( id ) { + /* NOTE: trap inconsistencies */ + assert( BER_BVISNULL( &id->eid_ndn ) ); + } if ( ndn->bv_len > BACKSQL_MAX_DN_LEN ) { Debug( LDAP_DEBUG_TRACE, - "backsql_dn2id(): DN \"%s\" (%ld bytes) " - "exceeds max DN length (%d):\n", + " backsql_dn2id(\"%s\"): DN length=%ld " + "exceeds max DN length %d:\n", ndn->bv_val, ndn->bv_len, BACKSQL_MAX_DN_LEN ); return LDAP_OTHER; } @@ -121,16 +160,20 @@ backsql_dn2id( { if ( id != NULL ) { #ifdef BACKSQL_ARBITRARY_KEY - ber_dupbv( &id->eid_id, &backsql_baseObject_bv ); - ber_dupbv( &id->eid_keyval, &backsql_baseObject_bv ); + ber_dupbv_x( &id->eid_id, &backsql_baseObject_bv, + op->o_tmpmemctx ); + ber_dupbv_x( &id->eid_keyval, &backsql_baseObject_bv, + op->o_tmpmemctx ); #else /* ! BACKSQL_ARBITRARY_KEY */ id->eid_id = BACKSQL_BASEOBJECT_ID; id->eid_keyval = BACKSQL_BASEOBJECT_KEYVAL; #endif /* ! BACKSQL_ARBITRARY_KEY */ id->eid_oc_id = BACKSQL_BASEOBJECT_OC; - ber_dupbv( &id->eid_ndn, &bi->sql_baseObject->e_nname ); - ber_dupbv( &id->eid_dn, &bi->sql_baseObject->e_name ); + ber_dupbv_x( &id->eid_ndn, &bi->sql_baseObject->e_nname, + op->o_tmpmemctx ); + ber_dupbv_x( &id->eid_dn, &bi->sql_baseObject->e_name, + op->o_tmpmemctx ); id->eid_next = NULL; } @@ -139,13 +182,15 @@ backsql_dn2id( } /* begin TimesTen */ - Debug( LDAP_DEBUG_TRACE, "id_query \"%s\"\n", bi->sql_id_query, 0, 0 ); - assert( bi->sql_id_query ); + Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): id_query \"%s\"\n", + ndn->bv_val, bi->sql_id_query, 0 ); + assert( bi->sql_id_query != NULL ); rc = backsql_Prepare( dbh, &sth, bi->sql_id_query, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, - "backsql_dn2id(): error preparing SQL:\n%s", - bi->sql_id_query, 0, 0); + " backsql_dn2id(\"%s\"): " + "error preparing SQL:\n %s", + ndn->bv_val, bi->sql_id_query, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); res = LDAP_OTHER; goto done; @@ -175,8 +220,9 @@ backsql_dn2id( upperdn[ i ] = '\0'; ldap_pvt_str2upper( upperdn ); - Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(): upperdn=\"%s\"\n", - upperdn, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " + "upperdn=\"%s\"\n", + ndn->bv_val, upperdn, 0 ); ber_str2bv( upperdn, 0, 0, &tbbDN ); } else { @@ -184,8 +230,9 @@ backsql_dn2id( AC_MEMCPY( upperdn, realndn.bv_val, realndn.bv_len + 1 ); ldap_pvt_str2upper( upperdn ); Debug( LDAP_DEBUG_TRACE, - "==>backsql_dn2id(): upperdn=\"%s\"\n", - upperdn, 0, 0 ); + " backsql_dn2id(\"%s\"): " + "upperdn=\"%s\"\n", + ndn->bv_val, upperdn, 0 ); ber_str2bv( upperdn, 0, 0, &tbbDN ); } else { @@ -196,9 +243,9 @@ backsql_dn2id( rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &tbbDN ); if ( rc != SQL_SUCCESS) { /* end TimesTen */ - Debug( LDAP_DEBUG_TRACE, "backsql_dn2id(): " + Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "error binding dn=\"%s\" parameter:\n", - tbbDN.bv_val, 0, 0 ); + ndn->bv_val, tbbDN.bv_val, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); res = LDAP_OTHER; goto done; @@ -206,18 +253,18 @@ backsql_dn2id( rc = SQLExecute( sth ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_dn2id(): " + Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "error executing query (\"%s\", \"%s\"):\n", - bi->sql_id_query, tbbDN.bv_val, 0 ); + ndn->bv_val, bi->sql_id_query, tbbDN.bv_val ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); res = LDAP_OTHER; goto done; } - backsql_BindRowAsStrings( sth, &row ); + backsql_BindRowAsStrings_x( sth, &row, op->o_tmpmemctx ); rc = SQLFetch( sth ); if ( BACKSQL_SUCCESS( rc ) ) { - char buf[BUFSIZ]; + char buf[ SLAP_TEXT_BUFLEN ]; #ifdef LDAP_DEBUG snprintf( buf, sizeof(buf), @@ -225,56 +272,104 @@ backsql_dn2id( row.cols[ 0 ], row.cols[ 1 ], row.cols[ 2 ], row.cols[ 3 ] ); Debug( LDAP_DEBUG_TRACE, - "<==backsql_dn2id(): %s\n", buf, 0, 0 ); + " backsql_dn2id(\"%s\"): %s\n", + ndn->bv_val, buf, 0 ); #endif /* LDAP_DEBUG */ res = LDAP_SUCCESS; if ( id != NULL ) { struct berval dn; + id->eid_next = NULL; + #ifdef BACKSQL_ARBITRARY_KEY - ber_str2bv( row.cols[ 0 ], 0, 1, &id->eid_id ); - ber_str2bv( row.cols[ 1 ], 0, 1, &id->eid_keyval ); + 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, NULL ); - 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 ); - } - - 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 { res = LDAP_NO_SUCH_OBJECT; - Debug( LDAP_DEBUG_TRACE, "<==backsql_dn2id(): no match\n", - 0, 0, 0 ); + if ( matched ) { + struct berval pdn = *ndn; + + /* + * Look for matched + */ + rs->sr_matched = NULL; + while ( !be_issuffix( op->o_bd, &pdn ) ) { + char *matchedDN = NULL; + + dnParent( &pdn, &pdn ); + + /* + * Empty DN ("") defaults to LDAP_SUCCESS + */ + rs->sr_err = backsql_dn2id( op, rs, dbh, &pdn, id, 0, 1 ); + switch ( rs->sr_err ) { + case LDAP_NO_SUCH_OBJECT: + /* try another one */ + break; + + case LDAP_SUCCESS: + matchedDN = pdn.bv_val; + /* fail over to next case */ + + default: + rs->sr_err = LDAP_NO_SUCH_OBJECT; + rs->sr_matched = matchedDN; + goto done; + } + } + } } - 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 ); if ( sth != SQL_NULL_HSTMT ) { SQLFreeStmt( sth, SQL_DROP ); } @@ -288,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; @@ -312,7 +408,7 @@ backsql_count_children( /* begin TimesTen */ Debug(LDAP_DEBUG_TRACE, "children id query \"%s\"\n", bi->sql_has_children_query, 0, 0); - assert( bi->sql_has_children_query ); + assert( bi->sql_has_children_query != NULL ); rc = backsql_Prepare( dbh, &sth, bi->sql_has_children_query, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, @@ -344,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 ); @@ -373,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; @@ -398,10 +511,26 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) RETCODE rc; SQLHSTMT sth = SQL_NULL_HSTMT; BACKSQL_ROW_NTS row; - int i; - - assert( at ); - assert( bsi ); + unsigned long i, + k = 0, + oldcount = 0, + res = 0; +#ifdef BACKSQL_COUNTQUERY + unsigned count, + j, + append = 0; + SQLLEN countsize = sizeof( count ); + Attribute *attr = NULL; + + slap_mr_normalize_func *normfunc = NULL; +#endif /* BACKSQL_COUNTQUERY */ +#ifdef BACKSQL_PRETTY_VALIDATE + slap_syntax_validate_func *validate = NULL; + slap_syntax_transform_func *pretty = NULL; +#endif /* BACKSQL_PRETTY_VALIDATE */ + + assert( at != NULL ); + assert( bsi != NULL ); #ifdef BACKSQL_ARBITRARY_KEY Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): " @@ -415,29 +544,162 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) bsi->bsi_c_eid->eid_keyval ); #endif /* ! BACKSQL_ARBITRARY_KEY */ +#ifdef BACKSQL_PRETTY_VALIDATE + 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; + } +#endif /* BACKSQL_PRETTY_VALIDATE */ + +#ifdef BACKSQL_COUNTQUERY + 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 + * fragmentation that can result from loading the values in + * one by one and using realloc() + */ + rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_countquery, 0 ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error preparing count query: %s\n", + at->bam_countquery, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); + return 1; + } + + rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, + &bsi->bsi_c_eid->eid_keyval ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error binding key value parameter\n", 0, 0, 0 ); + SQLFreeStmt( sth, SQL_DROP ); + return 1; + } + + rc = SQLExecute( sth ); + if ( ! BACKSQL_SUCCESS( rc ) ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error executing attribute count query '%s'\n", + at->bam_countquery, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); + SQLFreeStmt( sth, SQL_DROP ); + return 1; + } + + SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_LONG, + (SQLPOINTER)&count, + (SQLINTEGER)sizeof( count ), + &countsize ); + + rc = SQLFetch( sth ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error fetch results of count query: %s\n", + at->bam_countquery, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); + SQLFreeStmt( sth, SQL_DROP ); + return 1; + } + + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "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_true_ad ); + if ( attr != NULL ) { + BerVarray tmp; + + if ( attr->a_vals != NULL ) { + oldcount = attr->a_numvals; + } + + tmp = ch_realloc( attr->a_vals, ( oldcount + count + 1 ) * sizeof( struct berval ) ); + if ( tmp == NULL ) { + return 1; + } + attr->a_vals = tmp; + memset( &attr->a_vals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) ); + + if ( normfunc ) { + tmp = ch_realloc( attr->a_nvals, ( oldcount + count + 1 ) * sizeof( struct berval ) ); + if ( tmp == NULL ) { + return 1; + } + attr->a_nvals = tmp; + memset( &attr->a_nvals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) ); + + } else { + attr->a_nvals = attr->a_vals; + } + attr->a_numvals += count; + + } else { + append = 1; + + /* Make space for the array of values */ + 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; + } + if ( normfunc ) { + attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) ); + if ( attr->a_nvals == NULL ) { + ch_free( attr->a_vals ); + ch_free( attr ); + return 1; + + } + + } else { + attr->a_nvals = attr->a_vals; + } + } +#endif /* BACKSQL_COUNTQUERY */ + rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_query, 0 ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + 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; } rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &bsi->bsi_c_eid->eid_keyval ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + 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; } #ifdef BACKSQL_TRACE #ifdef BACKSQL_ARBITRARY_KEY - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " "query=\"%s\" keyval=%s\n", at->bam_query, bsi->bsi_c_eid->eid_keyval.bv_val, 0 ); #else /* !BACKSQL_ARBITRARY_KEY */ - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " "query=\"%s\" keyval=%d\n", at->bam_query, bsi->bsi_c_eid->eid_keyval, 0 ); #endif /* ! BACKSQL_ARBITRARY_KEY */ @@ -445,39 +707,178 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) rc = SQLExecute( sth ); if ( ! BACKSQL_SUCCESS( rc ) ) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " "error executing attribute query \"%s\"\n", 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 */ + for ( rc = SQLFetch( sth ), k = 0; + BACKSQL_SUCCESS( rc ); + rc = SQLFetch( sth ), k++ ) + { + for ( i = 0; i < (unsigned long)row.ncols; i++ ) { - rc = SQLFetch( sth ); - for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) { - for ( i = 0; i < row.ncols; i++ ) { if ( row.value_len[ i ] > 0 ) { - struct berval bv; + struct berval bv; + int retval; +#ifdef BACKSQL_TRACE + AttributeDescription *ad = NULL; + const char *text; + + retval = slap_bv2ad( &row.col_names[ i ], &ad, &text ); + if ( retval != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "==>backsql_get_attr_vals(\"%s\"): " + "unable to find AttributeDescription %s " + "in schema (%d)\n", + bsi->bsi_e->e_name.bv_val, + row.col_names[ i ].bv_val, retval ); + res = 1; + goto done; + } - bv.bv_val = row.cols[ i ]; -#if 0 - bv.bv_len = row.col_prec[ i ]; -#else - /* - * FIXME: what if a binary - * is fetched? + if ( ad != at->bam_ad ) { + Debug( LDAP_DEBUG_ANY, + "==>backsql_get_attr_vals(\"%s\"): " + "column name %s differs from " + "AttributeDescription %s\n", + bsi->bsi_e->e_name.bv_val, + ad->ad_cname.bv_val, + at->bam_ad->ad_cname.bv_val ); + res = 1; + goto done; + } +#endif /* BACKSQL_TRACE */ + + /* ITS#3386, ITS#3113 - 20070308 + * If a binary is fetched? + * must use the actual size read + * from the database. */ - bv.bv_len = strlen( row.cols[ i ] ); -#endif - backsql_entry_addattr( bsi->bsi_e, - &row.col_names[ i ], &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_true_ad->ad_type->sat_syntax, + &bv, &pbv, bsi->bsi_op->o_tmpmemctx ); + bv = pbv; + + } else { + retval = validate( at->bam_true_ad->ad_type->sat_syntax, + &bv ); + } + + if ( retval != LDAP_SUCCESS ) { + char buf[ SLAP_TEXT_BUFLEN ]; + + /* FIXME: we're ignoring invalid values, + * but we're accepting the attributes; + * should we fail at all? */ + snprintf( buf, sizeof( buf ), + "unable to %s value #%lu " + "of AttributeDescription %s", + pretty ? "prettify" : "validate", + k - oldcount, + at->bam_ad->ad_cname.bv_val ); + Debug( LDAP_DEBUG_TRACE, + "==>backsql_get_attr_vals(\"%s\"): " + "%s (%d)\n", + bsi->bsi_e->e_name.bv_val, buf, retval ); + continue; + } +#endif /* BACKSQL_PRETTY_VALIDATE */ + +#ifndef BACKSQL_COUNTQUERY + (void)backsql_entry_addattr( bsi->bsi_e, + at->bam_true_ad, &bv, + bsi->bsi_op->o_tmpmemctx ); + +#else /* BACKSQL_COUNTQUERY */ + if ( normfunc ) { + struct berval nbv; + + retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + at->bam_true_ad->ad_type->sat_syntax, + at->bam_true_ad->ad_type->sat_equality, + &bv, &nbv, bsi->bsi_op->o_tmpmemctx ); + if ( retval != LDAP_SUCCESS ) { + char buf[ SLAP_TEXT_BUFLEN ]; + + /* FIXME: we're ignoring invalid values, + * but we're accepting the attributes; + * should we fail at all? */ + snprintf( buf, sizeof( buf ), + "unable to normalize value #%lu " + "of AttributeDescription %s", + k - oldcount, + at->bam_ad->ad_cname.bv_val ); + Debug( LDAP_DEBUG_TRACE, + "==>backsql_get_attr_vals(\"%s\"): " + "%s (%d)\n", + bsi->bsi_e->e_name.bv_val, buf, retval ); + +#ifdef BACKSQL_PRETTY_VALIDATE + if ( pretty ) { + bsi->bsi_op->o_tmpfree( bv.bv_val, + bsi->bsi_op->o_tmpmemctx ); + } +#endif /* BACKSQL_PRETTY_VALIDATE */ + + continue; + } + ber_dupbv( &attr->a_nvals[ j ], &nbv ); + bsi->bsi_op->o_tmpfree( nbv.bv_val, + bsi->bsi_op->o_tmpmemctx ); + } + + ber_dupbv( &attr->a_vals[ j ], &bv ); + + assert( j < oldcount + count ); + j++; +#endif /* BACKSQL_COUNTQUERY */ + +#ifdef BACKSQL_PRETTY_VALIDATE + if ( pretty ) { + bsi->bsi_op->o_tmpfree( bv.bv_val, + bsi->bsi_op->o_tmpmemctx ); + } +#endif /* BACKSQL_PRETTY_VALIDATE */ + #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "prec=%d\n", (int)row.col_prec[ i ], 0, 0 ); + } else { Debug( LDAP_DEBUG_TRACE, "NULL value " "in this row for attribute \"%s\"\n", @@ -487,28 +888,48 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) } } - backsql_FreeRow( &row ); +#ifdef BACKSQL_COUNTQUERY + if ( BER_BVISNULL( &attr->a_vals[ 0 ] ) ) { + /* don't leave around attributes with no values */ + attr_free( attr ); + + } else if ( append ) { + Attribute **ap; + + for ( ap = &bsi->bsi_e->e_attrs; (*ap) != NULL; ap = &(*ap)->a_next ) + /* goto last */ ; + *ap = attr; + } +#endif /* BACKSQL_COUNTQUERY */ + 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 backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid ) { - backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; + Operation *op = bsi->bsi_op; + backsql_info *bi = (backsql_info *)op->o_bd->be_private; int i; int rc; - AttributeDescription *ad_oc = slap_schema.si_ad_objectClass; Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 ); - assert( bsi->bsi_e ); + assert( bsi->bsi_e != NULL ); memset( bsi->bsi_e, 0, sizeof( Entry ) ); @@ -525,25 +946,30 @@ backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid ) goto done; } - ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, bsi->bsi_op->o_tmpmemctx ); - ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, bsi->bsi_op->o_tmpmemctx ); + ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, op->o_tmpmemctx ); + ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, op->o_tmpmemctx ); 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 + /* FIXME: unused */ bsi->bsi_e->e_id = eid->eid_id; #endif /* ! BACKSQL_ARBITRARY_KEY */ - rc = attr_merge_normalize_one( bsi->bsi_e, ad_oc, - &bsi->bsi_oc->bom_oc->soc_cname, - bsi->bsi_op->o_tmpmemctx ); + rc = attr_merge_normalize_one( bsi->bsi_e, + slap_schema.si_ad_objectClass, + &bsi->bsi_oc->bom_oc->soc_cname, + bsi->bsi_op->o_tmpmemctx ); if ( rc != LDAP_SUCCESS ) { - entry_clean( bsi->bsi_e ); + backsql_entry_clean( op, bsi->bsi_e ); return rc; } @@ -557,7 +983,7 @@ backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid ) } else { Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " "custom attribute list\n", 0, 0, 0 ); - for ( i = 0; bsi->bsi_attrs[ i ].an_name.bv_val; i++ ) { + for ( i = 0; !BER_BVISNULL( &bsi->bsi_attrs[ i ].an_name ); i++ ) { backsql_at_map_rec **vat; AttributeName *an = &bsi->bsi_attrs[ i ]; int j; @@ -567,7 +993,7 @@ backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid ) * because subtypes are already dealt with * by backsql_supad2at() */ - for ( j = 0; bsi->bsi_attrs[ j ].an_name.bv_val; j++ ) { + for ( j = 0; !BER_BVISNULL( &bsi->bsi_attrs[ j ].an_name ); j++ ) { /* skip self */ if ( j == i ) { continue; @@ -615,39 +1041,74 @@ next:; } } - if ( global_schemacheck ) { - const char *text = NULL; - char textbuf[ 1024 ]; - size_t textlen = sizeof( textbuf ); - struct berval bv[ 2 ]; - struct berval soc; - int rc; - - bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname; - bv[ 1 ].bv_val = NULL; + if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER ) + || 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 bv[ 2 ], + *nvals; + int rc = LDAP_SUCCESS; + + a = attr_find( bsi->bsi_e->e_attrs, + slap_schema.si_ad_objectClass ); + if ( a != NULL ) { + nvals = a->a_nvals; - rc = structural_class( bv, &soc, NULL, - &text, textbuf, textlen ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): " - "structural_class() failed %d (%s)\n", - bsi->bsi_e->e_name.bv_val, - rc, text ? text : "" ); - entry_clean( bsi->bsi_e ); - return rc; - } + } else { + bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname; + BER_BVZERO( &bv[ 1 ] ); + nvals = bv; + } - if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER ) - || an_find( bsi->bsi_attrs, &AllOper ) - || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) ) - { - rc = attr_merge_normalize_one( bsi->bsi_e, - slap_schema.si_ad_structuralObjectClass, - &soc, bsi->bsi_op->o_tmpmemctx ); + rc = structural_class( nvals, &soc, NULL, + &text, textbuf, textlen, op->o_tmpmemctx ); if ( rc != LDAP_SUCCESS ) { - entry_clean( bsi->bsi_e ); + Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): " + "structural_class() failed %d (%s)\n", + bsi->bsi_e->e_name.bv_val, + rc, text ? text : "" ); + backsql_entry_clean( op, bsi->bsi_e ); return rc; } + + 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 " + "is subclass of 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 ); + } + + } else { + soc = bsi->bsi_oc->bom_oc; + } + + rc = attr_merge_normalize_one( bsi->bsi_e, + slap_schema.si_ad_structuralObjectClass, + &soc->soc_cname, + bsi->bsi_op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + backsql_entry_clean( op, bsi->bsi_e ); + return rc; } }