/** * \retval DB_NOT_EXISTS if the recovery table does not exist */ int ListMgr_RecovStatus( lmgr_t * p_mgr, lmgr_recov_stat_t * p_stats ) { int rc, i; result_handle_t result; char * status[3]; /* test if a RECOVERY table already exist, and contains entries */ rc = db_exec_sql_quiet( &p_mgr->conn, "SELECT recov_status,COUNT(*),SUM(size) FROM "RECOV_TABLE " GROUP BY recov_status", &result ); if (rc) return rc; /* table exists, fill status tab */ p_stats->total = 0; for (i = 0; i < RS_COUNT; i++ ) { p_stats->status_count[i] = 0; p_stats->status_size[i] = 0; } while ( (rc = db_next_record( &p_mgr->conn, &result, status, 3 )) != DB_END_OF_LIST ) { long long cnt; uint64_t sz; if (rc) return rc; cnt = str2bigint( status[1] ); if ( cnt == -1LL) return DB_INVALID_ARG; sz = str2size( status[2] ); if ( sz == -1LL) return DB_INVALID_ARG; p_stats->total += cnt; if ( status[0] != NULL ) { int idx = str2int( status[0] ); if ((idx >= RS_COUNT) || (idx == -1) ) return DB_REQUEST_FAILED; p_stats->status_count[idx] = cnt; p_stats->status_size[idx] = sz; } } db_result_free( &p_mgr->conn, &result ); return 0; }
/** * \retval DB_NOT_EXISTS if the recovery table does not exist */ static int expected_recov_status( lmgr_t * p_mgr, lmgr_recov_stat_t * p_stats ) { int rc, i; result_handle_t result; char * status[5]; /* test if a RECOVERY table already exist, and contains entries */ rc = db_exec_sql_quiet( &p_mgr->conn, "SELECT status,type,COUNT(*),(size=0) as empty,SUM(size) FROM "RECOV_TABLE " GROUP BY status,type,empty", &result ); if (rc) return rc; /* @TODO manage dirs and symlinks differently */ p_stats->total = 0; for (i = 0; i < RS_COUNT; i++ ) { p_stats->status_count[i] = 0; p_stats->status_size[i] = 0; } while ( (rc = db_next_record( &p_mgr->conn, &result, status, 5 )) != DB_END_OF_LIST ) { long long cnt; uint64_t sz; int isempty; if (rc) return rc; cnt = str2bigint( status[2] ); if ( cnt == -1LL) return DB_INVALID_ARG; isempty = str2int( status[3] ); if ( isempty == -1) return DB_INVALID_ARG; sz = str2size( status[4] ); if ( sz == -1LL) return DB_INVALID_ARG; p_stats->total += cnt; if ( status[0] != NULL ) { int st = str2int( status[0] ); /* archived entries: file and (optionally) symlinks */ if (!strcasecmp(status[1], STR_TYPE_FILE)) { if (isempty) { p_stats->status_count[RS_FILE_EMPTY] += cnt; p_stats->status_size[RS_FILE_EMPTY] += sz; } else { switch (st) { case STATUS_NEW: p_stats->status_count[RS_NOBACKUP] += cnt; p_stats->status_size[RS_NOBACKUP] += sz; break; case STATUS_MODIFIED: case STATUS_ARCHIVE_RUNNING: p_stats->status_count[RS_FILE_DELTA] += cnt; p_stats->status_size[RS_FILE_DELTA] += sz; break; case STATUS_SYNCHRO: case STATUS_RELEASED: p_stats->status_count[RS_FILE_OK] += cnt; p_stats->status_size[RS_FILE_OK] += sz; break; } } } else if (!strcasecmp(status[1], STR_TYPE_LINK) || !strcasecmp(status[1], STR_TYPE_DIR)) { /* symlinks and dirs always recoverable from DB */ p_stats->status_count[RS_NON_FILE] += cnt; p_stats->status_size[RS_NON_FILE] += sz; } else { /* non recoverable : special entry like fifo, blk, ... */ p_stats->status_count[RS_NOBACKUP] += cnt; p_stats->status_size[RS_NOBACKUP] += sz; } } } db_result_free( &p_mgr->conn, &result ); return 0; }
/** * Builds a report from database. */ struct lmgr_report_t *ListMgr_Report(lmgr_t *p_mgr, const report_field_descr_t * report_desc_array, unsigned int report_descr_count, const profile_field_descr_t * profile_descr, const lmgr_filter_t *p_filter, const lmgr_iter_opt_t *p_opt) { unsigned int i; char attrname[128]; lmgr_report_t *p_report; int rc; table_enum query_tab; /* supported report fields: ENTRIES, ANNEX_INFO or ACCT */ bool use_acct_table = false; lmgr_iter_opt_t opt = { 0 }; unsigned int profile_len = 0; unsigned int ratio = 0; struct field_count fcnt = { 0 }; GString *req = NULL; GString *fields = NULL; GString *where = NULL; GString *having = NULL; GString *group_by = NULL; GString *order_by = NULL; GString *filter_name = NULL; /* check profile argument and increase output array if needed */ if (profile_descr != NULL) { if (profile_descr->attr_index != ATTR_INDEX_size) { DisplayLog(LVL_CRIT, LISTMGR_TAG, "Profile on attribute '%s' (index=%u) is not supported", field_name(profile_descr->attr_index), profile_descr->attr_index); return NULL; } profile_len = SZ_PROFIL_COUNT; if (profile_descr->range_ratio_len > 0) ratio = 1; } /* allocate a new report structure */ p_report = (lmgr_report_t *) MemAlloc(sizeof(lmgr_report_t)); if (!p_report) return NULL; p_report->p_mgr = p_mgr; p_report->result = (struct result *)MemCalloc(report_descr_count + profile_len + ratio, sizeof(struct result)); if (!p_report->result) goto free_report; p_report->result_count = report_descr_count + profile_len + ratio; p_report->profile_count = profile_len; p_report->ratio_count = ratio; if (profile_descr != NULL) p_report->profile_attr = ATTR_INDEX_size; /* initially, no char * tab allocated */ p_report->str_tab = NULL; if (p_opt) opt = *p_opt; fields = g_string_new(NULL); group_by = g_string_new(NULL); order_by = g_string_new(NULL); having = g_string_new(NULL); where = g_string_new(NULL); if (full_acct(report_desc_array, report_descr_count, p_filter) && !opt.force_no_acct) { listmgr_optimizedstat(p_report, p_mgr, report_descr_count, report_desc_array, profile_descr, fields, group_by, order_by, having, where); use_acct_table = true; } else { /* not only ACCT table */ /* sorting by ratio first */ if (profile_descr && profile_descr->range_ratio_len > 0) { if (profile_descr->attr_index == ATTR_INDEX_size) { coma_if_needed(order_by); if (profile_descr->range_ratio_sort == SORT_ASC) g_string_append(order_by, "sizeratio ASC"); else g_string_append(order_by, "sizeratio DESC"); } } for (i = 0; i < report_descr_count; i++) { /* no field for count or distinct count */ if (report_desc_array[i].report_type != REPORT_COUNT && report_desc_array[i].report_type != REPORT_COUNT_DISTINCT) { /* in what table is this field ? */ if (is_main_field(report_desc_array[i].attr_index)) fcnt.nb_main++; else if (is_annex_field(report_desc_array[i].attr_index)) fcnt.nb_annex++; else { /* Not supported yet */ DisplayLog(LVL_CRIT, LISTMGR_TAG, "Error: report on attribute '%s' (index=%u) is not supported (report item #%u).", field_name(report_desc_array[i].attr_index), report_desc_array[i].attr_index, i); rc = DB_NOT_SUPPORTED; goto free_str; } } sprintf(attrname, "attr%u", i); /* what kind of stat on this field ? */ switch (report_desc_array[i].report_type) { case REPORT_MIN: coma_if_needed(fields); g_string_append_printf(fields, "MIN(%s) as %s", field_str(report_desc_array[i]. attr_index), attrname); p_report->result[i].type = field_type(report_desc_array[i].attr_index); break; case REPORT_MAX: coma_if_needed(fields); g_string_append_printf(fields, "MAX(%s) as %s", field_str(report_desc_array[i]. attr_index), attrname); p_report->result[i].type = field_type(report_desc_array[i].attr_index); break; case REPORT_AVG: coma_if_needed(fields); g_string_append_printf(fields, "ROUND(AVG(%s)) as %s", field_str(report_desc_array[i]. attr_index), attrname); p_report->result[i].type = field_type(report_desc_array[i].attr_index); break; case REPORT_SUM: coma_if_needed(fields); g_string_append_printf(fields, "SUM(%s) as %s", field_str(report_desc_array[i]. attr_index), attrname); p_report->result[i].type = field_type(report_desc_array[i].attr_index); break; case REPORT_COUNT: coma_if_needed(fields); g_string_append_printf(fields, "COUNT(*) as %s", attrname); p_report->result[i].type = DB_BIGUINT; break; case REPORT_COUNT_DISTINCT: coma_if_needed(fields); g_string_append_printf(fields, "COUNT(DISTINCT(%s)) as %s", field_str(report_desc_array[i]. attr_index), attrname); p_report->result[i].type = DB_BIGUINT; break; case REPORT_GROUP_BY: coma_if_needed(fields); g_string_append_printf(fields, "%s as %s", field_str(report_desc_array[i]. attr_index), attrname); coma_if_needed(group_by); g_string_append(group_by, attrname); p_report->result[i].type = field_type(report_desc_array[i].attr_index); break; } /* is this field sorted ? */ append_sort_order(order_by, attrname, report_desc_array[i].sort_flag); /* is this field filtered ? */ listmgr_fieldfilter(p_report, p_mgr, report_desc_array, attrname, having, where, i); p_report->result[i].flags = field_flag(report_desc_array[i].attr_index); } /* generate size profile */ if (profile_descr != NULL) { if (profile_descr->attr_index == ATTR_INDEX_size) { coma_if_needed(fields); g_string_append(fields, "SUM(size=0)"); for (i = 1; i < SZ_PROFIL_COUNT - 1; i++) g_string_append_printf(fields, ",SUM(" SZRANGE_FUNC "(size)=%u)", i - 1); g_string_append_printf(fields, ",SUM(" SZRANGE_FUNC "(size)>=%u)", SZ_PROFIL_COUNT - 1); for (i = 0; i < SZ_PROFIL_COUNT; i++) p_report->result[i + report_descr_count].type = DB_BIGUINT; if (profile_descr->range_ratio_len > 0) { /* add ratio field and sort it */ coma_if_needed(fields); g_string_append_printf(fields, "SUM(size>=%llu", SZ_MIN_BY_INDEX(profile_descr-> range_ratio_start)); /* is the last range = 1T->inf ? */ if (profile_descr->range_ratio_start + profile_descr->range_ratio_len >= SZ_PROFIL_COUNT) g_string_append(fields, ")"); else g_string_append_printf(fields, " and size<%llu)", SZ_MIN_BY_INDEX(profile_descr->range_ratio_start + profile_descr->range_ratio_len)); g_string_append(fields, "/COUNT(*) as sizeratio"); } } } } /* process filter */ if (!(no_filter(p_filter))) { if (full_acct(report_desc_array, report_descr_count, p_filter) && !opt.force_no_acct) { int filter_acct; /* filter on acct fields only */ filter_acct = filter2str(p_mgr, where, p_filter, T_ACCT, (!GSTRING_EMPTY(where) ? AOF_LEADING_SEP : 0) | AOF_PREFIX); if (filter_acct > 0) use_acct_table = true; } else { /* process NAMES filters apart, as with must then join with * DISTINCT(id) */ filter_where(p_mgr, p_filter, &fcnt, where, (!GSTRING_EMPTY(where) ? AOF_LEADING_SEP : 0) | AOF_SKIP_NAME); filter_name = g_string_new(NULL); fcnt.nb_names = filter2str(p_mgr, filter_name, p_filter, T_DNAMES, 0); } } /* start building the whole request */ req = g_string_new("SELECT "); g_string_append_printf(req, "%s FROM ", fields->str); /* FROM clause */ if (use_acct_table) { g_string_append(req, ACCT_TABLE); query_tab = T_ACCT; } else { bool distinct; filter_from(p_mgr, &fcnt, req, &query_tab, &distinct, AOF_SKIP_NAME); if (filter_name != NULL && !GSTRING_EMPTY(filter_name)) { g_string_append_printf(req, " INNER JOIN (SELECT DISTINCT(id)" " FROM " DNAMES_TABLE " WHERE %s) N" " ON %s.id=N.id", filter_name->str, table2name(query_tab)); /* FIXME: what if NAMES is the query tab? */ } /* FIXME: do the same for stripe items */ } /* Build the request */ if (!GSTRING_EMPTY(where)) g_string_append_printf(req, " WHERE %s", where->str); if (!GSTRING_EMPTY(group_by)) g_string_append_printf(req, " GROUP BY %s", group_by->str); if (!GSTRING_EMPTY(having)) g_string_append_printf(req, " HAVING %s", having->str); if (!GSTRING_EMPTY(order_by)) g_string_append_printf(req, " ORDER BY %s", order_by->str); /* iterator opt */ if (opt.list_count_max > 0) g_string_append_printf(req, " LIMIT %u", opt.list_count_max); retry: /* execute request (expect that ACCT table does not exists) */ if (use_acct_table) rc = db_exec_sql_quiet(&p_mgr->conn, req->str, &p_report->select_result); else rc = db_exec_sql(&p_mgr->conn, req->str, &p_report->select_result); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; /* if the ACCT table does exist, switch to standard mode */ if (use_acct_table && (rc == DB_NOT_EXISTS)) { lmgr_iter_opt_t new_opt; if (p_opt != NULL) new_opt = *p_opt; else new_opt.list_count_max = 0; new_opt.force_no_acct = true; DisplayLog(LVL_EVENT, LISTMGR_TAG, "No accounting info: switching to standard query mode"); g_string_free(req, TRUE); g_string_free(fields, TRUE); g_string_free(group_by, TRUE); g_string_free(order_by, TRUE); g_string_free(having, TRUE); g_string_free(where, TRUE); if (filter_name != NULL) g_string_free(filter_name, TRUE); return ListMgr_Report(p_mgr, report_desc_array, report_descr_count, profile_descr, p_filter, &new_opt); } free_str: /* these are always allocated */ g_string_free(fields, TRUE); g_string_free(group_by, TRUE); g_string_free(order_by, TRUE); g_string_free(having, TRUE); g_string_free(where, TRUE); /* these may not be allocated */ if (req != NULL) g_string_free(req, TRUE); if (filter_name != NULL) g_string_free(filter_name, TRUE); if (rc == DB_SUCCESS) return p_report; /* error */ MemFree(p_report->result); free_report: MemFree(p_report); return NULL; } /* ListMgr_Report */
int insert_stripe_info( lmgr_t * p_mgr, PK_ARG_T pk, int validator, const stripe_info_t * p_stripe, const stripe_items_t * p_items, int update_if_exists ) { int i, rc; int created = FALSE; if ( p_stripe == NULL ) return DB_INVALID_ARG; do { char short_query[4096]; /* First insert info into STRIPE_INFO_TABLE, * so if a file is already present with the same id, * we will remove its previous stripe info */ sprintf( short_query, "INSERT INTO " STRIPE_INFO_TABLE "(id,validator, stripe_count,stripe_size,pool_name) " "VALUES ("DPK",%u,%u,%u,'%s')", pk, validator, p_stripe->stripe_count, ( unsigned int ) p_stripe->stripe_size, p_stripe->pool_name ); if ( update_if_exists ) rc = db_exec_sql_quiet( &p_mgr->conn, short_query, NULL ); else rc = db_exec_sql( &p_mgr->conn, short_query, NULL ); if ( rc == 0 ) { created = TRUE; } else if ( (rc == DB_ALREADY_EXISTS) && update_if_exists ) { /* remove previous stripe info */ DisplayLog( LVL_EVENT, LISTMGR_TAG, "A stripe info already exists with this identifier, removing it" ); rc = delete_stipe_info( p_mgr, pk ); } if ( rc != 0 ) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "DB query failed in %s line %d: code=%d: %s", __FUNCTION__, __LINE__, rc, db_errmsg( &p_mgr->conn, short_query, 4096 ) ); return rc; } } while ( !created ); /* retry loop in case a similar entry already exists */ /* then insert stripe items */ if ( (p_items != NULL) && (p_items->count > 0) ) { ssize_t len; unsigned int est_len; char *query = NULL; /* estimate query size = fix part + stripe_count * ( 4 + pklen + ost_idx_len ) * = ~64(oversize to 128) + stripe_count * 4 + 128 */ est_len = 128 + p_items->count * 128; DisplayLog( LVL_FULL, LISTMGR_TAG, "Estimated query size for %u stripe = %u", p_items->count, est_len ); query = MemAlloc(est_len); if (query == NULL) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "Not enough memory to build SQL query (length = %u)", est_len ); return DB_NO_MEMORY; } strcpy( query, "INSERT INTO " STRIPE_ITEMS_TABLE "(id, storage_item) VALUES " ); len = strlen( query ); /* first stripe item */ len += snprintf( query + len, est_len - len, "("DPK",%u)", pk, p_items->stripe_units[0] ); /* next items */ for ( i = 1; i < p_items->count; i++ ) { len += snprintf( query + len, est_len - len, ",("DPK",%u)", pk, p_items->stripe_units[i] ); if ( len >= est_len ) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "Error in %s(): query too long (>%u bytes long), stripe_count=%d", __FUNCTION__, est_len, p_items->count ); MemFree( query ); return DB_BUFFER_TOO_SMALL; } } rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) { DisplayLog( LVL_CRIT, LISTMGR_TAG, "DB query failed in %s line %d: code=%d: %s", __FUNCTION__, __LINE__, rc, db_errmsg( &p_mgr->conn, query, 4096 ) ); MemFree( query ); return rc; } MemFree( query ); } return 0; }
/** * Builds a report from database. */ struct lmgr_report_t *ListMgr_Report( lmgr_t * p_mgr, const report_field_descr_t * report_desc_array, unsigned int report_descr_count, const profile_field_descr_t * profile_descr, const lmgr_filter_t * p_filter, const lmgr_iter_opt_t * p_opt ) { unsigned int i; /* A query consists of 5 parts: * - List of fields to be selected * - FROM clause with joins * - WHERE clause (filters) * - GROUP BY clause * - ORBER BY clause */ char fields[1024] = ""; char from[512] = ""; char where[2048] = ""; char having[2048] = ""; char group_by[512] = ""; char order_by[512] = ""; char query[4096] = ""; /* filters on NAMES or STRIPE_ITEMS * must be managed differently, as they * can create duplicates (non uniq id) */ char name_filter_str[1024] = ""; char stripe_filter_str[1024] = ""; char *curr_field = fields; char *curr_group_by = group_by; char *curr_sort = order_by; char *curr_query = query; char *curr_where = where; char *curr_having = having; char attrname[128]; char attrstring[1024]; lmgr_report_t *p_report; int rc; table_enum query_tab; /* supported report fields: ENTRIES, ANNEX_INFO or ACCT */ int main_table_flag = FALSE; int annex_table_flag = FALSE; int acct_table_flag = FALSE; int filter_main = 0; int filter_annex = 0; int filter_stripe_info = 0; int filter_stripe_items = 0; int filter_names = 0; int filter_acct = 0; int full_acct = TRUE; lmgr_iter_opt_t opt = {0}; unsigned int profile_len = 0; unsigned int ratio = 0; /* check profile argument and increase output array if needed */ if (profile_descr != NULL) { if (profile_descr->attr_index != ATTR_INDEX_size) { DisplayLog(LVL_CRIT, LISTMGR_TAG, "Profile on attribute #%u is not supported", profile_descr->attr_index); return NULL; } profile_len = SZ_PROFIL_COUNT; if (profile_descr->range_ratio_len > 0) ratio = 1; } /* allocate a new report structure */ p_report = ( lmgr_report_t * ) MemAlloc( sizeof( lmgr_report_t ) ); if ( !p_report ) return NULL; p_report->p_mgr = p_mgr; p_report->result_type_array = ( db_type_t * ) MemCalloc( report_descr_count + profile_len + ratio, sizeof( db_type_t ) ); if ( !p_report->result_type_array ) goto free_report; p_report->result_count = report_descr_count + profile_len + ratio; p_report->profile_count = profile_len; p_report->ratio_count = ratio; if (profile_descr != NULL) p_report->profile_attr = ATTR_INDEX_size; /* initialy, no char * tab allocated */ p_report->str_tab = NULL; if (p_opt) opt = *p_opt; for ( i = 0; i < report_descr_count; i++ ) { if ( ( report_desc_array[i].report_type != REPORT_COUNT ) && #ifdef ATTR_INDEX_dircount report_desc_array[i].attr_index != ATTR_INDEX_dircount && #endif !is_acct_field( report_desc_array[i].attr_index ) && !is_acct_pk( report_desc_array[i].attr_index ) ) full_acct = FALSE; } if ( p_filter ) { if ( p_filter->filter_type == FILTER_SIMPLE ) { for ( i = 0; i < p_filter->filter_simple.filter_count; i++ ) { if ( !is_acct_pk( p_filter->filter_simple.filter_index[i] ) && !is_acct_field( p_filter->filter_simple.filter_index[i] ) ) full_acct = FALSE; } } } if ( full_acct && !opt.force_no_acct ) { listmgr_optimizedstat( p_report, p_mgr, report_descr_count, report_desc_array, profile_descr, fields, &curr_field, group_by, &curr_group_by, order_by, &curr_sort, having, &curr_having, where, &curr_where); acct_table_flag = TRUE; } else /* not only ACCT table */ { /* sorting by ratio first */ if (profile_descr && profile_descr->range_ratio_len > 0) { if ( profile_descr->attr_index == ATTR_INDEX_size ) { if (profile_descr->range_ratio_sort == SORT_ASC) add_string( order_by, curr_sort, "sizeratio ASC"); else add_string( order_by, curr_sort, "sizeratio DESC"); } } for ( i = 0; i < report_descr_count; i++ ) { /* no field for count or distinct count */ if ( report_desc_array[i].report_type != REPORT_COUNT && report_desc_array[i].report_type != REPORT_COUNT_DISTINCT ) { /* in what table is this field ? */ if ( is_main_field( report_desc_array[i].attr_index ) ) main_table_flag = TRUE; else if ( is_annex_field( report_desc_array[i].attr_index ) ) annex_table_flag = TRUE; else { /* Not supported yet */ DisplayLog( LVL_CRIT, LISTMGR_TAG, "Error: report on attribute #%u is not supported (report item #%u).", report_desc_array[i].attr_index, i ); goto free_field_tab; } } sprintf( attrname, "attr%u", i ); /* what kind of stat on this field ? */ switch ( report_desc_array[i].report_type ) { case REPORT_MIN: sprintf( attrstring, "MIN( %s ) as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = field_type( report_desc_array[i].attr_index ); break; case REPORT_MAX: sprintf( attrstring, "MAX( %s ) as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = field_type( report_desc_array[i].attr_index ); break; case REPORT_AVG: sprintf( attrstring, "ROUND(AVG( %s )) as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = field_type( report_desc_array[i].attr_index ); break; case REPORT_SUM: sprintf( attrstring, "SUM( %s ) as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = field_type( report_desc_array[i].attr_index ); break; case REPORT_COUNT: sprintf( attrstring, "COUNT(*) as %s", attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = DB_BIGUINT; break; case REPORT_COUNT_DISTINCT: sprintf( attrstring, "COUNT(DISTINCT(%s)) as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); p_report->result_type_array[i] = DB_BIGUINT; break; case REPORT_GROUP_BY: sprintf( attrstring, "%s as %s", field_str( report_desc_array[i].attr_index ), attrname ); add_string( fields, curr_field, attrstring ); add_string( group_by, curr_group_by, attrname ); p_report->result_type_array[i] = field_type( report_desc_array[i].attr_index ); break; } /* is this field sorted ? */ if ( report_desc_array[i].sort_flag == SORT_ASC ) { sprintf( attrstring, "%s ASC", attrname ); add_string( order_by, curr_sort, attrstring ); } else if ( report_desc_array[i].sort_flag == SORT_DESC ) { sprintf( attrstring, "%s DESC", attrname ); add_string( order_by, curr_sort, attrstring ); } /* is this field filtered ? */ listmgr_fieldfilter( p_report, p_mgr, report_desc_array, attrstring, attrname, having, &curr_having, where, &curr_where, i ); } /* generate size profile */ if (profile_descr != NULL) { if (profile_descr->attr_index == ATTR_INDEX_size) { add_string( fields, curr_field, "SUM(size=0)" ); for (i=1; i < SZ_PROFIL_COUNT-1; i++) curr_field += sprintf(curr_field, ",SUM("ACCT_SZ_VAL("size")"=%u)", i-1); curr_field += sprintf(curr_field, ",SUM("ACCT_SZ_VAL("size")">=%u)", i-1); for (i=0; i<SZ_PROFIL_COUNT; i++) p_report->result_type_array[i+report_descr_count] = DB_BIGUINT; if (profile_descr->range_ratio_len > 0) { /* add ratio field and sort it */ attrstring[0] = '\0'; char *curr_attr = attrstring; curr_attr += sprintf(curr_attr, "SUM(size>=%Lu", SZ_MIN_BY_INDEX(profile_descr->range_ratio_start)); /* is the last range = 1T->inf ? */ if (profile_descr->range_ratio_start + profile_descr->range_ratio_len >= SZ_PROFIL_COUNT) curr_attr += sprintf(curr_attr, ")"); else curr_attr += sprintf(curr_attr, " and size<%Lu)", SZ_MIN_BY_INDEX(profile_descr->range_ratio_start+profile_descr->range_ratio_len)); curr_attr += sprintf(curr_attr, "/COUNT(*) as sizeratio"); add_string( fields, curr_field, attrstring ); } } } } /* filter */ if ( p_filter ) { if ( ( full_acct && !opt.force_no_acct ) ) { filter_acct = filter2str( p_mgr, curr_where, p_filter, T_ACCT, ( where != curr_where ), TRUE ); curr_where += strlen( curr_where ); if ( filter_acct ) acct_table_flag =TRUE; } else { /* filter on main table? */ filter_main = filter2str( p_mgr, curr_where, p_filter, T_MAIN, ( where != curr_where ), TRUE ); curr_where += strlen( curr_where ); if ( filter_main ) main_table_flag = TRUE; /* filter on annex table? */ if ( annex_table ) { filter_annex = filter2str( p_mgr, curr_where, p_filter, T_ANNEX, (where != curr_where), TRUE ); curr_where += strlen( curr_where ); if ( filter_annex ) annex_table_flag = TRUE; } filter_stripe_info = filter2str( p_mgr, curr_where, p_filter, T_STRIPE_INFO, (where != curr_where), TRUE ); curr_where += strlen( curr_where ); /* filter on names table is particular as this may duplicate * entries when computing the report (multiple hardlinks) */ filter_names = filter2str(p_mgr, name_filter_str, p_filter, T_DNAMES, FALSE, FALSE ); /* filter on stripe items table is particular as this may duplicate * entries when computing the report (multiple stripes) */ filter_stripe_items = filter2str(p_mgr, stripe_filter_str, p_filter, T_STRIPE_ITEMS, FALSE, FALSE); } } /* FROM clause */ if ( acct_table_flag ) { strcpy( from, ACCT_TABLE ); query_tab = T_ACCT; } else { const char * first_table = NULL; char * curr_from = from; if ( main_table_flag ) { strcpy(from, MAIN_TABLE); curr_from = from + strlen(from); first_table = MAIN_TABLE; query_tab = T_MAIN; } if ( annex_table_flag ) { if (first_table) curr_from += sprintf(curr_from, " LEFT JOIN "ANNEX_TABLE" ON %s.id="ANNEX_TABLE".id", first_table); else { strcpy(from, ANNEX_TABLE); curr_from = from + strlen(from); first_table = ANNEX_TABLE; query_tab = T_ANNEX; } } if ( filter_stripe_info ) { if (first_table) curr_from += sprintf(curr_from, " INNER JOIN "STRIPE_INFO_TABLE" ON %s.id="STRIPE_INFO_TABLE".id", first_table); else { strcpy(from, STRIPE_INFO_TABLE); curr_from = from + strlen(from); first_table = STRIPE_INFO_TABLE; query_tab = T_STRIPE_INFO; } } if (filter_names) { if (first_table) curr_from += sprintf(curr_from," INNER JOIN (SELECT DISTINCT(id)" " FROM "DNAMES_TABLE" WHERE %s) N" " ON %s.id=N.id", name_filter_str, first_table); else { DisplayLog(LVL_CRIT, LISTMGR_TAG, "Unexpected case: "DNAMES_TABLE " table can't be the query table in %s()", __func__); goto free_field_tab; } } if (filter_stripe_items) { if (first_table) curr_from += sprintf(curr_from, " INNER JOIN (SELECT DISTINCT(id)" " FROM "STRIPE_ITEMS_TABLE" WHERE %s) SI" " ON %s.id=SI.id", stripe_filter_str, first_table); else { strcpy(from, STRIPE_ITEMS_TABLE); curr_from = from + strlen(from); strcpy(curr_where, stripe_filter_str); curr_where += strlen(curr_where); first_table = STRIPE_ITEMS_TABLE; query_tab = T_STRIPE_ITEMS; /* XXX the caller is supposed to select DISTINCT(id) in this case */ } } } /* Build the request */ curr_query += sprintf( query, "SELECT %s FROM %s", fields, from ); if ( where[0] ) { curr_query += sprintf( curr_query, " WHERE %s", where ); } if ( group_by[0] ) { curr_query += sprintf( curr_query, " GROUP BY %s", group_by ); } if ( having[0] ) { curr_query += sprintf( curr_query, " HAVING %s", having ); } if ( order_by[0] ) { curr_query += sprintf( curr_query, " ORDER BY %s", order_by ); } /* iterator opt */ if ( opt.list_count_max > 0 ) { curr_query += sprintf( curr_query, " LIMIT %u", opt.list_count_max ); } #ifdef _DEBUG_DB printf( "Report is specified by: %s\n", query ); #endif retry: /* execute request (expect that ACCT table does not exists) */ if (acct_table_flag) rc = db_exec_sql_quiet( &p_mgr->conn, query, &p_report->select_result ); else rc = db_exec_sql( &p_mgr->conn, query, &p_report->select_result ); if (lmgr_delayed_retry(p_mgr, rc)) goto retry; /* if the ACCT table does exist, switch to standard mode */ if ( acct_table_flag && (rc == DB_NOT_EXISTS)) { lmgr_iter_opt_t new_opt; if (p_opt != NULL) new_opt = *p_opt; else new_opt.list_count_max = 0; new_opt.force_no_acct = TRUE; DisplayLog( LVL_EVENT, LISTMGR_TAG, "No accounting info: switching to standard query mode" ); return ListMgr_Report( p_mgr, report_desc_array, report_descr_count, profile_descr, p_filter, &new_opt ); } if ( rc ) goto free_field_tab; else return p_report; /* error handlers */ free_field_tab: MemFree( p_report->result_type_array ); free_report: MemFree( p_report ); return NULL; } /* ListMgr_Report */