/** check if all fields and filters of a requested report and are in * ACCT_TABLE */ static bool full_acct(const report_field_descr_t *report_desc_array, unsigned int report_descr_count, const lmgr_filter_t *p_filter) { int i; for (i = 0; i < report_descr_count; i++) { if ((report_desc_array[i].report_type != REPORT_COUNT) && report_desc_array[i].attr_index != ATTR_INDEX_dircount && !is_acct_field(report_desc_array[i].attr_index) && !is_acct_pk(report_desc_array[i].attr_index)) return false; } if (!no_filter(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])) return false; } } } return true; }
/** * 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 */
static void listmgr_optimizedstat(lmgr_report_t *p_report, lmgr_t *p_mgr, unsigned int report_descr_count, const report_field_descr_t * report_desc_array, const profile_field_descr_t *profile_descr, GString *fields, GString *group_by, GString *order_by, GString *having, GString *where) { int i; /* sorting by ratio first */ if (profile_descr && profile_descr->range_ratio_len > 0) { if (profile_descr->attr_index == ATTR_INDEX_size) append_sort_order(order_by, "sizeratio", profile_descr->range_ratio_sort); } for (i = 0; i < report_descr_count; i++) { char attrname[128]; snprintf(attrname, sizeof(attrname), "attr%u", i); if ((report_desc_array[i].report_type == REPORT_COUNT) || is_acct_pk(report_desc_array[i].attr_index) || is_acct_field(report_desc_array[i].attr_index)) { switch (report_desc_array[i].report_type) { case REPORT_MIN: case REPORT_MAX: coma_if_needed(fields); g_string_append_printf(fields, "NULL as %s", attrname); p_report->result[i].type = DB_TEXT; break; case REPORT_AVG: coma_if_needed(fields); g_string_append_printf(fields, "ROUND(SUM(%s)/SUM(" ACCT_FIELD_COUNT ")) 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, "SUM(" ACCT_FIELD_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); } else { coma_if_needed(fields); g_string_append_printf(fields, "NULL as %s", attrname); p_report->result[i].type = DB_TEXT; } 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); } if (profile_descr) { /* XXX only size profile in managed for now */ if (profile_descr->attr_index == ATTR_INDEX_size) { for (i = 0; i < SZ_PROFIL_COUNT; i++) { coma_if_needed(fields); g_string_append_printf(fields, "SUM(%s)", sz_field[i]); /* count */ 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); /* case i == 0 */ g_string_append_printf(fields, "SUM(%s", sz_field[profile_descr-> range_ratio_start]); for (i = 1; i < profile_descr->range_ratio_len; i++) { g_string_append_printf(fields, "+%s", sz_field[profile_descr-> range_ratio_start + i]); } g_string_append(fields, ")/SUM(" ACCT_FIELD_COUNT ") as sizeratio"); } } } }
static void listmgr_optimizedstat( lmgr_report_t *p_report, lmgr_t * p_mgr, unsigned int report_descr_count, const report_field_descr_t *report_desc_array, const profile_field_descr_t * profile_descr, char *fields, char **curr_field, char *group_by, char **curr_group_by, char *order_by, char **curr_sort, char *having, char **curr_having, char *where, char **curr_where ) { char attrstring[1024]; int i; char attrname[128]; /* 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++ ) { sprintf( attrname, "attr%u", i ); if( is_acct_pk( report_desc_array[i].attr_index ) || is_acct_field( report_desc_array[i].attr_index ) || report_desc_array[i].report_type == REPORT_COUNT ) { switch ( report_desc_array[i].report_type ) { case REPORT_MIN: sprintf( attrstring, "NULL as %s", attrname ); add_string( fields, *curr_field, attrstring ); p_report->result_type_array[i] = DB_TEXT; break; case REPORT_MAX: sprintf( attrstring, "NULL as %s", attrname ); add_string( fields, *curr_field, attrstring ); p_report->result_type_array[i] = DB_TEXT; break; case REPORT_AVG: sprintf( attrstring, "ROUND(SUM(%s)/SUM(" ACCT_FIELD_COUNT ")) 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, "SUM(" ACCT_FIELD_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 ); } } else { sprintf( attrstring, "NULL as %s", attrname ); add_string( fields, *curr_field, attrstring ); p_report->result_type_array[i] = DB_TEXT; } listmgr_fieldfilter( p_report, p_mgr, report_desc_array, attrstring, attrname, having, curr_having, where, curr_where, i ); } if (profile_descr) { /* XXX only size profile in managed for now */ if (profile_descr->attr_index == ATTR_INDEX_size) { for (i = 0; i < SZ_PROFIL_COUNT; i++) { (*curr_field) += sprintf(*curr_field, "%sSUM(%s)", (fields==(*curr_field))?"":",", sz_field[i]); p_report->result_type_array[i+report_descr_count] = DB_BIGUINT; /* count */ } if (profile_descr->range_ratio_len > 0) { /* add ratio field and sort it */ attrstring[0] = '\0'; char *curr_attr = attrstring; for (i = 0; i < profile_descr->range_ratio_len; i++) { if (attrstring != curr_attr) curr_attr += sprintf(curr_attr, "+%s", sz_field[profile_descr->range_ratio_start + i]); else curr_attr += sprintf(curr_attr, "SUM(%s", sz_field[profile_descr->range_ratio_start + i]); } curr_attr += sprintf(curr_attr, ")/SUM("ACCT_FIELD_COUNT") as sizeratio"); add_string( fields, *curr_field, attrstring ); } } } }