risingwave_frontend/handler/
alter_resource_group.rs

1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use pgwire::pg_response::StatementType;
16use risingwave_common::bail;
17use risingwave_common::util::worker_util::DEFAULT_RESOURCE_GROUP;
18use risingwave_sqlparser::ast::{ObjectName, SetVariableValue, SetVariableValueSingle, Value};
19
20use super::{HandlerArgs, RwPgResponse};
21use crate::Binder;
22use crate::catalog::root_catalog::SchemaPath;
23use crate::catalog::table_catalog::TableType;
24use crate::error::{ErrorCode, Result};
25
26pub async fn handle_alter_resource_group(
27    handler_args: HandlerArgs,
28    obj_name: ObjectName,
29    resource_group: Option<SetVariableValue>,
30    stmt_type: StatementType,
31    deferred: bool,
32) -> Result<RwPgResponse> {
33    let session = handler_args.session;
34    let db_name = session.database();
35    let (schema_name, real_table_name) =
36        Binder::resolve_schema_qualified_name(&db_name, obj_name.clone())?;
37    let search_path = session.config().search_path();
38    let user_name = &session.auth_context().user_name;
39    let schema_path = SchemaPath::new(schema_name.as_deref(), &search_path, user_name);
40
41    risingwave_common::license::Feature::ResourceGroup
42        .check_available()
43        .map_err(|e| anyhow::anyhow!(e))?;
44
45    let table_id = {
46        let reader = session.env().catalog_reader().read_guard();
47
48        match stmt_type {
49            StatementType::ALTER_MATERIALIZED_VIEW => {
50                let (table, schema_name) =
51                    reader.get_created_table_by_name(&db_name, schema_path, &real_table_name)?;
52
53                match (table.table_type(), stmt_type) {
54                    (TableType::MaterializedView, StatementType::ALTER_MATERIALIZED_VIEW) => {}
55                    _ => {
56                        return Err(ErrorCode::InvalidInputSyntax(format!(
57                            "cannot alter resource group of {} {} by {}",
58                            table.table_type().to_prost().as_str_name(),
59                            table.name(),
60                            stmt_type,
61                        ))
62                        .into());
63                    }
64                }
65
66                session.check_privilege_for_drop_alter(schema_name, &**table)?;
67                table.id.table_id()
68            }
69            _ => bail!(
70                "invalid statement type for alter resource group: {:?}",
71                stmt_type
72            ),
73        }
74    };
75
76    let resource_group = resource_group
77        .map(resolve_resource_group)
78        .transpose()?
79        .flatten();
80
81    let mut builder = RwPgResponse::builder(stmt_type);
82
83    let catalog_writer = session.catalog_writer()?;
84    catalog_writer
85        .alter_resource_group(table_id, resource_group, deferred)
86        .await?;
87
88    if deferred {
89        builder = builder.notice("DEFERRED is used, please ensure that automatic parallelism control is enabled on the meta, otherwise, the alter will not take effect.".to_owned());
90    }
91
92    Ok(builder.into())
93}
94
95// Resolve the resource group from the given SetVariableValue.
96pub(crate) fn resolve_resource_group(resource_group: SetVariableValue) -> Result<Option<String>> {
97    Ok(match resource_group {
98        SetVariableValue::Single(SetVariableValueSingle::Ident(ident)) => Some(ident.real_value()),
99        SetVariableValue::Single(SetVariableValueSingle::Literal(Value::SingleQuotedString(v)))
100            if v.as_str().eq_ignore_ascii_case(DEFAULT_RESOURCE_GROUP) =>
101        {
102            None
103        }
104        SetVariableValue::Single(SetVariableValueSingle::Literal(Value::SingleQuotedString(v))) => {
105            Some(v)
106        }
107        SetVariableValue::Default => None,
108        _ => {
109            return Err(ErrorCode::InvalidInputSyntax(
110                "target resource group must be a valid string or default".to_owned(),
111            )
112            .into());
113        }
114    })
115}