-
Notifications
You must be signed in to change notification settings - Fork 632
refactor(frontend): rearrange column binding steps in create table handler #19917
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -261,50 +261,15 @@ pub fn bind_sql_columns(column_defs: &[ColumnDef]) -> Result<Vec<ColumnCatalog>> | |
Ok(columns) | ||
} | ||
|
||
fn check_generated_column_constraints( | ||
column_name: &String, | ||
column_id: ColumnId, | ||
expr: &ExprImpl, | ||
column_catalogs: &[ColumnCatalog], | ||
generated_column_names: &[String], | ||
pk_column_ids: &[ColumnId], | ||
) -> Result<()> { | ||
let input_refs = expr.collect_input_refs(column_catalogs.len()); | ||
for idx in input_refs.ones() { | ||
let referred_generated_column = &column_catalogs[idx].column_desc.name; | ||
if generated_column_names | ||
.iter() | ||
.any(|c| c == referred_generated_column) | ||
{ | ||
return Err(ErrorCode::BindError(format!( | ||
"Generated can not reference another generated column. \ | ||
But here generated column \"{}\" referenced another generated column \"{}\"", | ||
column_name, referred_generated_column | ||
)) | ||
.into()); | ||
} | ||
} | ||
|
||
if pk_column_ids.contains(&column_id) && expr.is_impure() { | ||
return Err(ErrorCode::BindError(format!( | ||
"Generated columns with impure expressions should not be part of the primary key. \ | ||
Here column \"{}\" is defined as part of the primary key.", | ||
column_name | ||
)) | ||
.into()); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Binds constraints that can be only specified in column definitions, | ||
/// currently generated columns and default columns. | ||
pub fn bind_sql_column_constraints( | ||
/// | ||
/// `generated_or_default_column` field in [`ColumnDesc`] will be set. | ||
pub fn bind_sql_columns_generated_and_default_constraints( | ||
session: &SessionImpl, | ||
table_name: String, | ||
column_catalogs: &mut [ColumnCatalog], | ||
columns: Vec<ColumnDef>, | ||
pk_column_ids: &[ColumnId], | ||
) -> Result<()> { | ||
let generated_column_names = { | ||
let mut names = vec![]; | ||
|
@@ -336,14 +301,19 @@ pub fn bind_sql_column_constraints( | |
) | ||
})?; | ||
|
||
check_generated_column_constraints( | ||
&column.name.real_value(), | ||
column_catalogs[idx].column_id(), | ||
&expr_impl, | ||
column_catalogs, | ||
&generated_column_names, | ||
pk_column_ids, | ||
)?; | ||
// Check if generated column references another generated column. | ||
let input_refs = expr_impl.collect_input_refs(column_catalogs.len()); | ||
for idx in input_refs.ones() { | ||
let referred_generated_column = &column_catalogs[idx].column_desc.name; | ||
if generated_column_names.contains(referred_generated_column) { | ||
return Err(ErrorCode::BindError(format!( | ||
"Generated can not reference another generated column. \ | ||
But here generated column \"{}\" referenced another generated column \"{}\"", | ||
column.name.real_value(), referred_generated_column | ||
)) | ||
.into()); | ||
} | ||
} | ||
|
||
column_catalogs[idx].column_desc.generated_or_default_column = Some( | ||
GeneratedOrDefaultColumn::GeneratedColumn(GeneratedColumnDesc { | ||
|
@@ -444,8 +414,14 @@ fn multiple_pk_definition_err() -> RwError { | |
|
||
/// Binds primary keys defined in SQL. | ||
/// | ||
/// It returns the columns together with `pk_column_ids`, and an optional row id column index if | ||
/// added. | ||
/// If `must_need_pk` is true and no primary key is specified, a `_row_id` column is added to the | ||
/// given `columns` vec as the primary key. | ||
/// | ||
/// Returns the (maybe) updated columns together with `pk_column_ids`, and an optional `_row_id` | ||
/// column index if added. | ||
/// | ||
/// Should be called after calling [`bind_sql_columns_generated_and_default_constraints`] so that | ||
/// it can check whether a generated column is valid for being part of the primary key, if any. | ||
pub fn bind_pk_and_row_id_on_relation( | ||
mut columns: Vec<ColumnCatalog>, | ||
pk_names: Vec<String>, | ||
|
@@ -487,6 +463,23 @@ pub fn bind_pk_and_row_id_on_relation( | |
)))?; | ||
} | ||
|
||
// Check if impure generated columns are part of the primary key. | ||
for column in &columns { | ||
Comment on lines
+466
to
+467
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This step used to be in |
||
let Some(expr) = column.generated_expr() else { | ||
continue; | ||
}; | ||
let expr = ExprImpl::from_expr_proto(&expr)?; | ||
|
||
if pk_column_ids.contains(&column.column_id()) && expr.is_impure() { | ||
return Err(ErrorCode::BindError(format!( | ||
"Generated columns with impure expressions should not be part of the primary key. \ | ||
Here column \"{}\" is defined as part of the primary key.", | ||
column.name() | ||
)) | ||
.into()); | ||
} | ||
} | ||
|
||
Ok((columns, pk_column_ids, row_id_index)) | ||
} | ||
|
||
|
@@ -568,7 +561,6 @@ pub(crate) async fn gen_create_table_plan_with_source( | |
|
||
/// `gen_create_table_plan` generates the plan for creating a table without an external stream | ||
/// source. | ||
#[allow(clippy::too_many_arguments)] | ||
pub(crate) fn gen_create_table_plan( | ||
context: OptimizerContext, | ||
table_name: ObjectName, | ||
|
@@ -583,53 +575,50 @@ pub(crate) fn gen_create_table_plan( | |
c.column_desc.column_id = col_id_gen.generate(&*c)?; | ||
} | ||
|
||
bind_sql_columns_generated_and_default_constraints( | ||
context.session_ctx(), | ||
table_name.real_value(), | ||
&mut columns, | ||
column_defs.clone(), | ||
)?; | ||
|
||
let (_, secret_refs, connection_refs) = context.with_options().clone().into_parts(); | ||
if !secret_refs.is_empty() || !connection_refs.is_empty() { | ||
return Err(crate::error::ErrorCode::InvalidParameterValue("Secret reference and Connection reference are not allowed in options when creating table without external source".to_owned()).into()); | ||
} | ||
|
||
let pk_names = bind_sql_pk_names(&column_defs, bind_table_constraints(&constraints)?)?; | ||
|
||
let watermark_descs = bind_source_watermark( | ||
context.session_ctx(), | ||
table_name.real_value(), | ||
source_watermarks, | ||
&columns, | ||
)?; | ||
|
||
gen_create_table_plan_without_source( | ||
context, | ||
table_name, | ||
columns, | ||
column_defs, | ||
constraints, | ||
source_watermarks, | ||
pk_names, | ||
watermark_descs, | ||
col_id_gen.into_version(), | ||
props, | ||
) | ||
} | ||
|
||
#[allow(clippy::too_many_arguments)] | ||
pub(crate) fn gen_create_table_plan_without_source( | ||
context: OptimizerContext, | ||
table_name: ObjectName, | ||
columns: Vec<ColumnCatalog>, | ||
column_defs: Vec<ColumnDef>, | ||
constraints: Vec<TableConstraint>, | ||
source_watermarks: Vec<SourceWatermark>, | ||
pk_names: Vec<String>, | ||
watermark_descs: Vec<WatermarkDesc>, | ||
version: TableVersion, | ||
props: CreateTableProps, | ||
) -> Result<(PlanRef, PbTable)> { | ||
// XXX: Why not bind outside? | ||
let pk_names = bind_sql_pk_names(&column_defs, bind_table_constraints(&constraints)?)?; | ||
let (mut columns, pk_column_ids, row_id_index) = | ||
let (columns, pk_column_ids, row_id_index) = | ||
bind_pk_and_row_id_on_relation(columns, pk_names, true)?; | ||
|
||
let watermark_descs: Vec<WatermarkDesc> = bind_source_watermark( | ||
context.session_ctx(), | ||
table_name.real_value(), | ||
source_watermarks, | ||
&columns, | ||
)?; | ||
|
||
bind_sql_column_constraints( | ||
context.session_ctx(), | ||
table_name.real_value(), | ||
&mut columns, | ||
column_defs, | ||
&pk_column_ids, | ||
)?; | ||
let session = context.session_ctx().clone(); | ||
|
||
let db_name = session.database(); | ||
|
@@ -857,18 +846,17 @@ pub(crate) fn gen_create_table_plan_for_cdc_table( | |
c.column_desc.column_id = col_id_gen.generate(&*c)?; | ||
} | ||
|
||
let (mut columns, pk_column_ids, _row_id_index) = | ||
bind_pk_and_row_id_on_relation(columns, pk_names, true)?; | ||
|
||
// NOTES: In auto schema change, default value is not provided in column definition. | ||
bind_sql_column_constraints( | ||
bind_sql_columns_generated_and_default_constraints( | ||
context.session_ctx(), | ||
table_name.real_value(), | ||
&mut columns, | ||
column_defs, | ||
&pk_column_ids, | ||
)?; | ||
|
||
let (columns, pk_column_ids, _row_id_index) = | ||
bind_pk_and_row_id_on_relation(columns, pk_names, true)?; | ||
|
||
let definition = context.normalized_sql().to_owned(); | ||
|
||
let pk_column_indices = { | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This inlines the function.