MCPcopy Create free account
hub / github.com/MaterializeInc/materialize / is_compatible

Method is_compatible

src/sql-server-util/src/inspect.rs:623–691  ·  view source on GitHub ↗

Returns true if the DDL event is a compatible change, or false if it is not. This performs a naive parsing of the DDL command looking for modification of columns 1. ALTER TABLE .. ALTER COLUMN 2. ALTER TABLE .. DROP COLUMN See

(&self, included_columns: &[Arc<str>])

Source from the content-addressed store, hash-verified

621 ///
622 /// See <https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-table-transact-sql?view=sql-server-ver17>
623 pub fn is_compatible(&self, included_columns: &[Arc<str>]) -> bool {
624 // TODO (maz): This is currently a basic check that doesn't take into account type changes.
625 // At some point, we will need to move this to SqlServerTableDesc and expand it.
626 let mut words = self.ddl_command.split_ascii_whitespace();
627 match (
628 words.next().map(str::to_ascii_lowercase).as_deref(),
629 words.next().map(str::to_ascii_lowercase).as_deref(),
630 ) {
631 (Some("alter"), Some("table")) => {
632 let mut peekable = words.peekable();
633 let mut compatible = true;
634 while compatible && let Some(token) = peekable.next() {
635 compatible = match token.to_ascii_lowercase().as_str() {
636 "alter" | "drop" => {
637 let target = peekable.next();
638 match target {
639 // Targeting a column
640 Some(t) if t.eq_ignore_ascii_case("column") => {
641 let mut all_excluded = true;
642 while let Some(tok) = peekable.next() {
643 // The column name(s) can be preceeded by the pair of keywords "IF EXISTS", so we want to skip those.
644 match tok.to_ascii_lowercase().as_str() {
645 "if" | "exists" | "," | "column" => continue,
646 col_str => {
647 // If any column is in the included list, then it is not okay to alter/drop it
648 // The col_str token may be a comma-separated list of columns as whitespace is not required
649 // between column names in SQL Server DDL.
650 if !col_str.trim_matches(',').split(',').all(
651 |col_name| {
652 !included_columns.iter().any(|included| {
653 included.eq_ignore_ascii_case(
654 col_name.trim_matches(
655 ['[', ']', '"'].as_ref(),
656 ),
657 )
658 })
659 },
660 ) {
661 all_excluded = false;
662 break;
663 }
664 // If this is the only/last column, then we can break out of the while loop.
665 // Check if this string has no trailing comma, and if not, peek to see if the next token
666 // contains a leading comma.
667 if !col_str.ends_with(",") {
668 match peekable.peek() {
669 Some(x) if x.starts_with(",") => continue,
670 _ => break,
671 }
672 }
673 }
674 };
675 }
676 all_excluded
677 }
678 // No target token after "alter" or "drop"
679 None => false,
680 // Other targets are considered compatible

Callers 2

test_caseFunction · 0.45
renderFunction · 0.45

Calls 9

allMethod · 0.80
anyMethod · 0.80
mapMethod · 0.45
nextMethod · 0.45
as_strMethod · 0.45
splitMethod · 0.45
iterMethod · 0.45
as_refMethod · 0.45
peekMethod · 0.45

Tested by

no test coverage detected