int ListMgr_Insert(lmgr_t *p_mgr, entry_id_t *p_id, attr_set_t *p_info, int update_if_exists) { int rc; char buff[4096]; /* retry the whole transaction when the error is retryable */ retry: rc = lmgr_begin(p_mgr); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) return rc; rc = listmgr_batch_insert_no_tx(p_mgr, &p_id, &p_info, 1, update_if_exists); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) { lmgr_rollback(p_mgr); DisplayLog(LVL_CRIT, LISTMGR_TAG, "DB query failed in %s line %d: code=%d: %s", __FUNCTION__, __LINE__, rc, db_errmsg(&p_mgr->conn, buff, 4096)); return rc; } rc = lmgr_commit(p_mgr); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; /* success, count it */ if (!rc) p_mgr->nbop[OPIDX_INSERT]++; return rc; }
/** * Insert a batch of entries into the database. * All entries must have the same attr mask. */ int ListMgr_BatchInsert(lmgr_t * p_mgr, entry_id_t ** p_ids, attr_set_t ** p_attrs, unsigned int count, int update_if_exists) { int rc; char buff[4096]; if (count == 0) return DB_SUCCESS; else if (p_ids == NULL || p_attrs == NULL) RBH_BUG("NULL pointer argument"); /* read only fields in info mask? */ if (readonly_attr_set & p_attrs[0]->attr_mask) { DisplayLog(LVL_MAJOR, LISTMGR_TAG, "Error: trying to insert read only values: attr_mask=%#x", readonly_attr_set & p_attrs[0]->attr_mask); return DB_INVALID_ARG; } /* retry the whole transaction when the error is retryable */ retry: /* We want insert operation set to be atomic */ rc = lmgr_begin(p_mgr); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) return rc; rc = listmgr_batch_insert_no_tx(p_mgr, p_ids, p_attrs, count, update_if_exists); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; else if (rc) { lmgr_rollback(p_mgr); DisplayLog(LVL_CRIT, LISTMGR_TAG, "DB query failed in %s line %d: code=%d: %s", __FUNCTION__, __LINE__, rc, db_errmsg(&p_mgr->conn, buff, 4096)); return rc; } rc = lmgr_commit(p_mgr); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; /* success, count it */ if (!rc) { if (update_if_exists) p_mgr->nbop[OPIDX_UPDATE] += count; else p_mgr->nbop[OPIDX_INSERT] += count; } return rc; }
int ListMgr_Update( lmgr_t * p_mgr, const entry_id_t * p_id, const attr_set_t * p_update_set ) { int rc, main_count, annex_count; char query[4096]; char fields[4096]; char annex_fields[4096]; DEF_PK(pk); int nb_tables = 0; /* read only fields in info mask? */ if ( readonly_attr_set & p_update_set->attr_mask ) { DisplayLog( LVL_MAJOR, LISTMGR_TAG, "Error: trying to update read only values: attr_mask=%#x", readonly_attr_set & p_update_set->attr_mask ); return DB_INVALID_ARG; } rc = entry_id2pk( p_mgr, p_id, FALSE, PTR_PK(pk) ); if (rc) return rc; /* check how many tables are to be updated */ if ( main_fields( p_update_set->attr_mask ) ) { main_count = attrset2updatelist( p_mgr, fields, p_update_set, T_MAIN, FALSE ); if ( main_count < 0 ) return -main_count; if ( main_count > 0 ) nb_tables++; } else main_count = 0; if ( annex_table && annex_fields( p_update_set->attr_mask ) ) { annex_count = attrset2updatelist( p_mgr, annex_fields, p_update_set, T_ANNEX, FALSE ); if ( annex_count < 0 ) return -annex_count; if ( annex_count > 0 ) nb_tables++; } else annex_count = 0; if ( stripe_fields( p_update_set->attr_mask ) ) nb_tables += 2; /* if only 1 table is impacted, switch to autocommit mode */ if ( nb_tables > 1 ) { /* @todo in the case of sqlite, we may want to do periodic commit * instead of systematic one. */ rc = lmgr_begin( p_mgr ); if ( rc ) return rc; } /* update main table */ if ( main_count > 0 ) { sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id="DPK, fields, pk ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } /* update annex table (if any) */ if ( annex_count > 0 ) { sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id="DPK, annex_fields, pk ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } /* insert new stripe info if provided (and eventually remove previous values) */ if ( ATTR_MASK_TEST( p_update_set, stripe_info ) ) { rc = insert_stripe_info( p_mgr, pk, VALID(p_id), &ATTR( p_update_set, stripe_info ), ATTR_MASK_TEST( p_update_set, stripe_items ) ? &ATTR( p_update_set, stripe_items ) : NULL, TRUE ); if ( rc ) goto rollback; } if ( nb_tables > 1 ) return lmgr_commit( p_mgr ); else return DB_SUCCESS; rollback: lmgr_rollback( p_mgr ); return rc; }
int ListMgr_MassUpdate( lmgr_t * p_mgr, const lmgr_filter_t * p_filter, const attr_set_t * p_attr_set ) { char query[4096]; char filter_str_main[2048]; char filter_str_annex[2048]; char filter_str_stripe_info[2048]; char filter_str_stripe_units[2048]; int filter_main = 0; int filter_annex = 0; int filter_stripe_info = 0; int filter_stripe_units = 0; int rc, count; int impact_all = FALSE; int filter_unic = FALSE; char fields[2048]; char tmp_table_name[256]; int tmp_table_created = FALSE; filter_str_main[0] = '\0'; filter_str_annex[0] = '\0'; filter_str_stripe_info[0] = '\0'; filter_str_stripe_units[0] = '\0'; /* /!\ possible cases: * - simplest: the fields of the filter and the attributes to be changed are in the same table * - harder: the fields of the filter are in the same table and attributes are in another different table */ /* 1) check the location of filters */ if ( p_filter ) { filter_main = filter2str( p_mgr, filter_str_main, p_filter, T_MAIN, FALSE, FALSE ); if ( annex_table ) filter_annex = filter2str( p_mgr, filter_str_annex, p_filter, T_ANNEX, FALSE, FALSE ); else filter_annex = 0; filter_stripe_info = filter2str( p_mgr, filter_str_stripe_info, p_filter, T_STRIPE_INFO, FALSE, FALSE ); filter_stripe_units = filter2str( p_mgr, filter_str_stripe_units, p_filter, T_STRIPE_ITEMS,FALSE, FALSE ); if ( filter_main + filter_annex + filter_stripe_info + filter_stripe_units == 0 ) { /* all records */ impact_all = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Empty filter: all records will be affected" ); } else if ( filter_main && !( filter_annex || filter_stripe_info || filter_stripe_units ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " MAIN_TABLE " table" ); } else if ( filter_annex && !( filter_main || filter_stripe_info || filter_stripe_units ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " ANNEX_TABLE " table" ); } else if ( filter_stripe_info && !( filter_main || filter_annex || filter_stripe_units ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " STRIPE_INFO_TABLE " table" ); } else if ( filter_stripe_units && !( filter_main || filter_annex || filter_stripe_info ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " STRIPE_ITEMS_TABLE " table" ); } else DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter on several tables: " MAIN_TABLE ":%d, " ANNEX_TABLE ":%d, " STRIPE_INFO_TABLE ":%d, " STRIPE_ITEMS_TABLE ":%d", filter_main, filter_annex, filter_stripe_info, filter_stripe_units ); } else { impact_all = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Empty filter: all records will be affected" ); } /* 2) check if attributes to be changed are in MAIN table */ /* 3) if filters are in MAIN table too, make a simple update statement */ /* 4) if not, make a compound request: update xxx set xxx WHERE pk in ( select pk from ... where ... ) */ rc = lmgr_begin( p_mgr ); if ( rc ) return rc; /* perform updates on MAIN TABLE */ count = attrset2updatelist( p_mgr, fields, p_attr_set, T_MAIN, FALSE ); if ( count < 0 ) return -count; if ( count > 0 ) { DisplayLog( LVL_FULL, LISTMGR_TAG, "Update on " MAIN_TABLE " table" ); if ( impact_all ) { /* all records are impacted */ sprintf( query, "UPDATE " MAIN_TABLE " SET %s", fields ); } else if ( filter_unic && filter_main ) { /* update on the same table as filter */ sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE %s", fields, filter_str_main ); } else if ( filter_unic ) { /* update is on a different table than filter */ if ( filter_annex ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " ANNEX_TABLE " WHERE %s", tmp_table_name, filter_str_annex ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_units ) { if ( !tmp_table_created ) { sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); /* create temp table */ sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_ITEMS_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_units ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_info ) { if ( !tmp_table_created ) { sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); /* create temp table */ sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_INFO_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_info ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } } else { /* @todo mixed filter :-s */ rc = DB_NOT_SUPPORTED; goto rollback; } rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } /* update on annex table ? */ if ( annex_table ) { count = attrset2updatelist( p_mgr, fields, p_attr_set, T_ANNEX, FALSE ); if ( count < 0 ) return -count; if ( count > 0 ) { DisplayLog( LVL_FULL, LISTMGR_TAG, "Update on " ANNEX_TABLE " table" ); if ( impact_all ) { /* all records are impacted */ sprintf( query, "UPDATE " ANNEX_TABLE " SET %s", fields ); } else if ( filter_unic && filter_annex ) { /* update on the same table as filter */ sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE %s", fields, filter_str_annex ); } else if ( filter_unic ) { /* update is on a different table than filter */ if ( filter_main ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " MAIN_TABLE " WHERE %s", tmp_table_name, filter_str_main ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_units ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_ITEMS_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_units ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_info ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_INFO_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_info ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } } else { /* @todo mixed filter :-s */ rc = DB_NOT_SUPPORTED; goto rollback; } rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } } if ( ATTR_MASK_TEST( p_attr_set, stripe_info ) || ATTR_MASK_TEST( p_attr_set, stripe_items ) ) { /* XXX is there a case where stripe info is to be updated massively ? */ rc = DB_NOT_SUPPORTED; goto rollback; } if ( tmp_table_created ) { sprintf( query, "DROP TABLE %s", tmp_table_name ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } return lmgr_commit( p_mgr ); rollback: lmgr_rollback( p_mgr ); return rc; }