PostgreSQL: Support schema-qualified operator classes in CREATE INDEX (#2131)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run

This commit is contained in:
Denis Goncharenko 2025-12-16 13:07:11 +01:00 committed by GitHub
parent 9b8a2d1e22
commit cdeed32294
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 44 additions and 8 deletions

View file

@ -61,7 +61,7 @@ use crate::tokenizer::{Span, Token};
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct IndexColumn {
pub column: OrderByExpr,
pub operator_class: Option<Ident>,
pub operator_class: Option<ObjectName>,
}
impl From<Ident> for IndexColumn {

View file

@ -16933,10 +16933,10 @@ impl<'a> Parser<'a> {
fn parse_order_by_expr_inner(
&mut self,
with_operator_class: bool,
) -> Result<(OrderByExpr, Option<Ident>), ParserError> {
) -> Result<(OrderByExpr, Option<ObjectName>), ParserError> {
let expr = self.parse_expr()?;
let operator_class: Option<Ident> = if with_operator_class {
let operator_class: Option<ObjectName> = if with_operator_class {
// We check that if non of the following keywords are present, then we parse an
// identifier as operator class.
if self
@ -16945,7 +16945,7 @@ impl<'a> Parser<'a> {
{
None
} else {
self.maybe_parse(|parser| parser.parse_identifier())?
self.maybe_parse(|parser| parser.parse_object_name(false))?
}
} else {
None

View file

@ -2572,11 +2572,17 @@ fn parse_create_indices_with_operator_classes() {
IndexType::SPGiST,
IndexType::Custom("CustomIndexType".into()),
];
let operator_classes: [Option<Ident>; 4] = [
let operator_classes: [Option<ObjectName>; 4] = [
None,
Some("gin_trgm_ops".into()),
Some("gist_trgm_ops".into()),
Some("totally_not_valid".into()),
Some(ObjectName(vec![ObjectNamePart::Identifier(Ident::new(
"gin_trgm_ops",
))])),
Some(ObjectName(vec![ObjectNamePart::Identifier(Ident::new(
"gist_trgm_ops",
))])),
Some(ObjectName(vec![ObjectNamePart::Identifier(Ident::new(
"totally_not_valid",
))])),
];
for expected_index_type in indices {
@ -2713,6 +2719,36 @@ fn parse_create_indices_with_operator_classes() {
}
}
#[test]
fn parse_create_index_with_schema_qualified_operator_class() {
let sql = "CREATE INDEX my_index ON my_table USING HNSW (embedding public.vector_cosine_ops)";
match pg().verified_stmt(sql) {
Statement::CreateIndex(CreateIndex { columns, .. }) => {
assert_eq!(1, columns.len());
let idx_col = &columns[0];
// Verify the column name
match &idx_col.column.expr {
Expr::Identifier(ident) => {
assert_eq!("embedding", ident.value);
}
_ => panic!("Expected identifier expression"),
}
// Verify the schema-qualified operator class
assert_eq!(
Some(ObjectName(vec![
ObjectNamePart::Identifier(Ident::new("public")),
ObjectNamePart::Identifier(Ident::new("vector_cosine_ops")),
])),
idx_col.operator_class
);
}
_ => unreachable!(),
}
}
#[test]
fn parse_create_bloom() {
let sql =