Skip to content

feat(query): add billing_usage_daily table function#19784

Open
smallfish wants to merge 6 commits intodatabendlabs:mainfrom
smallfish:feat/add-billing-history-table-functions
Open

feat(query): add billing_usage_daily table function#19784
smallfish wants to merge 6 commits intodatabendlabs:mainfrom
smallfish:feat/add-billing-history-table-functions

Conversation

@smallfish
Copy link
Copy Markdown
Collaborator

@smallfish smallfish commented Apr 28, 2026

I hereby agree to the terms of the CLA available at: https://docs.databend.com/dev/policies/cla/

Summary

This PR adds a new Databend Cloud table function:

  • billing_usage_daily(start_date => 'YYYY-MM-DD', end_date => 'YYYY-MM-DD')

It returns unified daily billing usage rows for compute, storage, and cloud services.

The table function exposes common billing fields such as usage date, usage category, service type, resource name, usage quantity, billing amount, and currency. It also includes tags and details as JSONB-backed Variant columns for resource-specific metadata, so new billing categories or detail fields can be added without changing the SQL surface.

rate_unit is retained as the billing dimension descriptor. rate is reserved for future use and is currently returned as NULL when undisclosed.

This PR also adds the corresponding cloud-control gRPC billing contract and client wiring.

Example

select *
  from billing_usage_daily(start_date => '2026-03-01', end_date => '2026-03-31')
  order by usage_date, usage_type, resource_name;

Example output:

usage_date usage_type service_type resource_name usage usage_unit rate rate_unit usage_in_currency currency tags details
2026-03-30 compute WAREHOUSE_METERING default 684 second NULL second 0.190000000000 $ {...} {...}
2026-03-30 storage STORAGE 3785053449616 byte NULL tb_day 2.221000000000 $ {} {...}
2026-03-30 cloud services CLOUD_SERVICES 1 request NULL k_request 0.000000000000 $ {} {}

tags and details are abbreviated in the example.

Field Definitions

Column Type Description
usage_date Date Billing date
usage_type String Top-level usage category, such as compute, storage, or cloud services
service_type String More specific service classification, such as WAREHOUSE_METERING, STORAGE, or CLOUD_SERVICES
resource_name String Logical resource name; for compute rows this is typically the warehouse name; empty when not applicable
usage Decimal(38, 0) Usage quantity
usage_unit String Unit of usage, such as second, byte, or request
rate Nullable(Decimal(38, 12)) Reserved billing rate field; currently NULL when the rate is undisclosed
rate_unit String Billing dimension unit, such as second, tb_day, or k_request
usage_in_currency Decimal(38, 12) Billed amount for the row
currency String Billing currency, propagated from webapi billing configuration
tags Variant JSONB-backed resource tags; currently mainly used for compute / warehouse rows; empty object when no tags are present
details Variant JSONB-backed structured details for category-specific attributes

Details Examples

usage_type Example details Description
compute {"cluster_name":"cl-00000","max_clusters":1,"size":"XSmall"} Warehouse runtime metadata
storage {"read_requests":0,"write_requests":0,"kilo_read_request_price":"0.0004","kilo_write_request_price":"0.005"} Storage request-related details
cloud services {} Empty object when no extra details are present

Notes

  • The table function uses named argument syntax: billing_usage_daily(start_date => 'YYYY-MM-DD', end_date => 'YYYY-MM-DD').
  • start_date is required. end_date is optional and defaults to start_date.
  • The table function name and argument names are case-insensitive.
  • The cloud-control proto keeps decimal values as strings, while the query layer exposes typed Date and Decimal columns for SQL filtering, ordering, and aggregation.
  • tags and details are JSONB-backed Variant metadata fields and support SQL path access and filtering.
  • The table function is available only when cloud-control is configured.
  • Large result sets may be rejected by cloud-control with a clear error; query a smaller date range if that happens.

Tests

  • Unit Test
  • Logic Test
  • Benchmark Test
  • No Test - Explain why

Type of change

  • Bug Fix (non-breaking change which fixes an issue)
  • New Feature (non-breaking change which adds functionality)
  • Breaking Change (fix or feature that could cause existing functionality not to work as expected)
  • Documentation Update
  • Refactoring
  • Performance Improvement
  • Other (please describe):

This change is Reviewable

@github-actions github-actions Bot added the pr-feature this PR introduces a new feature to the codebase label Apr 28, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a3c0dc727

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/query/task_support/src/table_functions/billing_history_daily.rs Outdated
@smallfish smallfish requested review from bohutang and everpcpc April 28, 2026 07:28
Comment thread src/common/cloud_control/proto/task.proto Outdated
Comment thread src/common/cloud_control/proto/task.proto Outdated
@databendlabs databendlabs deleted a comment from github-actions Bot Apr 29, 2026
@smallfish smallfish changed the title feat(query): add BILLING_HISTORY_DAILY BILLING_HISTORY_WAREHOUSE_DAILY table functions feat(query): add billing_usage_daily table function Apr 29, 2026
@smallfish smallfish force-pushed the feat/add-billing-history-table-functions branch from 6106bfe to 84b5ef8 Compare April 30, 2026 02:26
@smallfish smallfish force-pushed the feat/add-billing-history-table-functions branch from 84b5ef8 to b89528c Compare April 30, 2026 02:32
@databendlabs databendlabs deleted a comment from github-actions Bot Apr 30, 2026
@databendlabs databendlabs deleted a comment from github-actions Bot Apr 30, 2026
@smallfish smallfish requested a review from everpcpc April 30, 2026 05:37
Comment thread src/query/task_support/src/table_functions/billing_usage_daily.rs Outdated
Comment thread src/query/service/src/table_functions/billing_usage_daily.rs
Comment thread src/common/cloud_control/proto/billing.proto
Copy link
Copy Markdown
Member

@bohutang bohutang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. I found a few design concerns from the Databend side:

  1. Billing should not be coupled to task-support / task config

billing_usage_daily is registered under #[cfg(feature = "task-support")] and inside if !config.task.on, and the implementation also lives in the task_support crate.

Billing usage is a cloud-control/account-level capability and does not seem task-specific. This makes the availability of billing_usage_daily depend on task-support and task server configuration, which is surprising from a Databend user/operator perspective.

Could we move this out of task_support or register it based on cloud-control/billing availability instead of the task config?

  1. Use typed columns instead of strings for core billing fields

The result schema exposes core billing fields as strings:

  • usage_date
  • usage
  • rate
  • usage_in_currency

These are expected to be queried with SQL predicates and aggregations, e.g. date filtering, ordering, SUM(usage_in_currency), etc. Returning them as String makes users cast them manually and can produce incorrect lexical ordering/filtering if they forget.

Even if the cloud-control proto keeps decimal values as strings to avoid precision loss, the query layer should convert them into Databend native types, e.g. Date for usage_date and Decimal for usage/currency fields.

  1. Do not mask non-permission errors as PermissionDenied

ensure_billing_usage_privilege currently treats any error from validate_privilege as a permission denial:

if ctx
    .validate_privilege(&GrantObject::Global, UserPrivilegeType::Super, false)
    .await
    .is_ok()
{
    return Ok(());
}

Err(ErrorCode::PermissionDenied(...))

This can hide non-permission failures such as invalid role state or meta-store errors and report them as PermissionDenied, which makes troubleshooting harder.

Could we match on the error code instead: return Ok(()) on success, customize only PERMISSION_DENIED, and propagate all other errors unchanged?

@smallfish
Copy link
Copy Markdown
Collaborator Author

smallfish commented Apr 30, 2026

success

  • Moved billing_usage_daily out of databend-query-task-support into query service table functions. It is no longer registered under task-support or gated by config.task.on; it is registered only when cloud_control_grpc_server_address is configured.

  • Updated the core result schema to use native types:

    • usage_date: Date
    • usage: Decimal(38, 0)
    • rate: Nullable(Decimal(38, 12)), with undisclosed/empty values mapped to NULL
    • usage_in_currency: Decimal(38, 12)

    The query layer still accepts decimal values from the cloud-control proto as strings, but now parses them into Databend native columns. Added SQL-level coverage for date/decimal predicates, rate is null, and sum(...).

  • Updated ensure_billing_usage_privilege to only rewrite PERMISSION_DENIED into the billing-specific permission message. Other errors from validate_privilege are now propagated unchanged.

cc @bohutang

@databendlabs databendlabs deleted a comment from github-actions Bot May 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

🤖 CI Job Analysis

Workflow: 25199794544

📊 Summary

  • Total Jobs: 87
  • Failed Jobs: 1
  • Retryable: 0
  • Code Issues: 1

NO RETRY NEEDED

All failures appear to be code/test issues requiring manual fixes.

🔍 Job Details

  • linux / test_unit: Not retryable (Code/Test)

🤖 About

Automated analysis using job annotations to distinguish infrastructure issues (auto-retried) from code/test issues (manual fixes needed).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-feature this PR introduces a new feature to the codebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants