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)?;
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.check_available()?;
42
43    let table_id = {
44        let reader = session.env().catalog_reader().read_guard();
45
46        match stmt_type {
47            StatementType::ALTER_MATERIALIZED_VIEW => {
48                let (table, schema_name) =
49                    reader.get_created_table_by_name(&db_name, schema_path, &real_table_name)?;
50
51                match (table.table_type(), stmt_type) {
52                    (TableType::MaterializedView, StatementType::ALTER_MATERIALIZED_VIEW) => {}
53                    _ => {
54                        return Err(ErrorCode::InvalidInputSyntax(format!(
55                            "cannot alter resource group of {} {} by {}",
56                            table.table_type().to_prost().as_str_name(),
57                            table.name(),
58                            stmt_type,
59                        ))
60                        .into());
61                    }
62                }
63
64                session.check_privilege_for_drop_alter(schema_name, &**table)?;
65                table.id.table_id()
66            }
67            _ => bail!(
68                "invalid statement type for alter resource group: {:?}",
69                stmt_type
70            ),
71        }
72    };
73
74    let resource_group = resource_group
75        .map(resolve_resource_group)
76        .transpose()?
77        .flatten();
78
79    let mut builder = RwPgResponse::builder(stmt_type);
80
81    let catalog_writer = session.catalog_writer()?;
82    catalog_writer
83        .alter_resource_group(table_id, resource_group, deferred)
84        .await?;
85
86    if deferred {
87        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());
88    }
89
90    Ok(builder.into())
91}
92
93// Resolve the resource group from the given SetVariableValue.
94pub(crate) fn resolve_resource_group(resource_group: SetVariableValue) -> Result<Option<String>> {
95    Ok(match resource_group {
96        SetVariableValue::Single(SetVariableValueSingle::Ident(ident)) => Some(ident.real_value()),
97        SetVariableValue::Single(SetVariableValueSingle::Literal(Value::SingleQuotedString(v)))
98            if v.as_str().eq_ignore_ascii_case(DEFAULT_RESOURCE_GROUP) =>
99        {
100            None
101        }
102        SetVariableValue::Single(SetVariableValueSingle::Literal(Value::SingleQuotedString(v))) => {
103            Some(v)
104        }
105        SetVariableValue::Default => None,
106        _ => {
107            return Err(ErrorCode::InvalidInputSyntax(
108                "target resource group must be a valid string or default".to_owned(),
109            )
110            .into());
111        }
112    })
113}