agent_patch
runs/2026-02-28__18-27-22__gpt-5-1-codex-mini/flux-pr-2096/flux-pr-2096.1-of-1.2026-02-28__18-27-22__gpt-5-1-codex-mini/agent-logs/agent.patch
23902 bytes
diff --git a/tmp/agent-patch-flux-pr-2096.1-of-1.2026-02-28__18-27-22__gpt-5-1-codex-mini/app/src/ast/ddl.rs b/app/src/ast/ddl.rs
index 286b16a..a02ea06 100644
--- a/tmp/agent-patch-flux-pr-2096.1-of-1.2026-02-28__18-27-22__gpt-5-1-codex-mini/app/src/ast/ddl.rs
+++ b/app/src/ast/ddl.rs
@@ -3952,3 +3952,209 @@ impl Spanned for DropFunction {
Span::empty()
}
}
+
+/// Operator name container used in PostgreSQL operator DDL statements.
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct PgOperator {
+ pub names: Vec<String>,
+}
+
+impl fmt::Display for PgOperator {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "OPERATOR({})", display_separated(&self.names, "."))
+ }
+}
+
+/// CREATE OPERATOR statement
+///
+/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createoperator.html)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct CreateOperator {
+ pub name: ObjectName,
+ pub function_name: ObjectName,
+ pub procedure_keyword: bool,
+ pub left_arg: Option<DataType>,
+ pub right_arg: Option<DataType>,
+ pub commutator: Option<PgOperator>,
+ pub negator: Option<PgOperator>,
+ pub restrict: Option<ObjectName>,
+ pub join: Option<ObjectName>,
+ pub hashes: bool,
+ pub merges: bool,
+}
+
+impl fmt::Display for CreateOperator {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut clauses = Vec::new();
+ let fn_keyword = if self.procedure_keyword { "PROCEDURE" } else { "FUNCTION" };
+ clauses.push(format!("{fn_keyword} = {function_name}", function_name = self.function_name));
+ if let Some(left) = &self.left_arg {
+ clauses.push(format!("LEFTARG = {left}"));
+ }
+ if let Some(right) = &self.right_arg {
+ clauses.push(format!("RIGHTARG = {right}"));
+ }
+ if let Some(commutator) = &self.commutator {
+ clauses.push(format!("COMMUTATOR = {commutator}"));
+ }
+ if let Some(negator) = &self.negator {
+ clauses.push(format!("NEGATOR = {negator}"));
+ }
+ if let Some(restrict) = &self.restrict {
+ clauses.push(format!("RESTRICT = {restrict}"));
+ }
+ if let Some(join) = &self.join {
+ clauses.push(format!("JOIN = {join}"));
+ }
+ if self.hashes {
+ clauses.push("HASHES".to_string());
+ }
+ if self.merges {
+ clauses.push("MERGES".to_string());
+ }
+ write!(f, "CREATE OPERATOR {name} ({clauses})", name = self.name, clauses = clauses.join(", "))
+ }
+}
+
+/// CREATE OPERATOR FAMILY statement
+///
+/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createopfamily.html)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct CreateOperatorFamily {
+ pub name: ObjectName,
+ pub using: Ident,
+}
+
+impl fmt::Display for CreateOperatorFamily {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "CREATE OPERATOR FAMILY {name} USING {method}", name = self.name, method = self.using)
+ }
+}
+
+/// CREATE OPERATOR CLASS statement
+///
+/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createopclass.html)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct CreateOperatorClass {
+ pub name: ObjectName,
+ pub is_default: bool,
+ pub data_type: DataType,
+ pub using: Ident,
+ pub family: Option<ObjectName>,
+ pub items: Vec<OperatorClassItem>,
+}
+
+impl fmt::Display for CreateOperatorClass {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "CREATE OPERATOR CLASS {name}", name = self.name)?;
+ if self.is_default {
+ write!(f, " DEFAULT")?;
+ }
+ write!(f, " FOR TYPE {data_type} USING {using}", data_type = self.data_type, using = self.using)?;
+ if let Some(family) = &self.family {
+ write!(f, " FAMILY {family}")?;
+ }
+ write!(f, " AS {}", display_comma_separated(&self.items))
+ }
+}
+
+/// PostgreSQL operator class sort modifiers.
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum OperatorClassSort {
+ Search,
+ OrderBy(ObjectName),
+}
+
+impl fmt::Display for OperatorClassSort {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ OperatorClassSort::Search => f.write_str("FOR SEARCH"),
+ OperatorClassSort::OrderBy(name) => write!(f, "FOR ORDER BY {name}"),
+ }
+ }
+}
+
+/// Operand type descriptor used inside operator class definitions.
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum OperatorClassOpType {
+ DataType(DataType),
+ None,
+}
+
+impl fmt::Display for OperatorClassOpType {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ OperatorClassOpType::DataType(dt) => fmt::Display::fmt(dt, f),
+ OperatorClassOpType::None => f.write_str("NONE"),
+ }
+ }
+}
+
+/// Items that can appear inside the `AS` block of CREATE OPERATOR CLASS.
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum OperatorClassItem {
+ Operator {
+ strategy_number: u64,
+ operator_name: PgOperator,
+ op_types: Option<Vec<OperatorClassOpType>>,
+ sort: Option<OperatorClassSort>,
+ },
+ Function {
+ support_number: u64,
+ op_types: Option<Vec<OperatorClassOpType>>,
+ function_name: ObjectName,
+ arguments: Vec<DataType>,
+ },
+ Storage {
+ storage_type: DataType,
+ },
+}
+
+impl fmt::Display for OperatorClassItem {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ OperatorClassItem::Operator {
+ strategy_number,
+ operator_name,
+ op_types,
+ sort,
+ } => {
+ write!(f, "OPERATOR {strategy_number} {operator_name}")?;
+ if let Some(op_types) = op_types {
+ write!(f, " ({})", display_comma_separated(op_types))?;
+ }
+ if let Some(sort) = sort {
+ write!(f, " {sort}")?;
+ }
+ Ok(())
+ }
+ OperatorClassItem::Function {
+ support_number,
+ op_types,
+ function_name,
+ arguments,
+ } => {
+ write!(f, "FUNCTION {support_number}")?;
+ if let Some(op_types) = op_types {
+ write!(f, " ({})", display_comma_separated(op_types))?;
+ }
+ write!(f, " {function_name} ({})", display_comma_separated(arguments))
+ }
+ OperatorClassItem::Storage { storage_type } => write!(f, "STORAGE {storage_type}"),
+ }
+ }
+}
diff --git a/tmp/agent-patch-flux-pr-2096.1-of-1.2026-02-28__18-27-22__gpt-5-1-codex-mini/app/src/ast/mod.rs b/app/src/ast/mod.rs
index aa3fb08..5bf8c53 100644
--- a/tmp/agent-patch-flux-pr-2096.1-of-1.2026-02-28__18-27-22__gpt-5-1-codex-mini/app/src/ast/mod.rs
+++ b/app/src/ast/mod.rs
@@ -65,11 +65,13 @@ pub use self::ddl::{
AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue,
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions, ColumnPolicy,
ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain,
- CreateExtension, CreateFunction, CreateIndex, CreateTable, CreateTrigger, CreateView,
+ CreateExtension, CreateFunction, CreateIndex, CreateOperator, CreateOperatorClass,
+ CreateOperatorFamily, CreateTable, CreateTrigger, CreateView,
Deduplicate, DeferrableInitial, DropBehavior, DropExtension, DropFunction, DropTrigger,
GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexColumn,
- IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, Owner, Partition,
+ IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, Owner,
+ OperatorClassItem, OperatorClassOpType, OperatorClassSort, PgOperator, Partition,
ProcedureParam, ReferentialAction, RenameTableNameKind, ReplicaIdentity, TagsColumnOption,
TriggerObjectKind, Truncate, UserDefinedTypeCompositeAttributeDef,
UserDefinedTypeInternalLength, UserDefinedTypeRangeOption, UserDefinedTypeRepresentation,
@@ -3308,6 +3310,21 @@ pub enum Statement {
/// ```
CreateIndex(CreateIndex),
/// ```sql
+ /// CREATE OPERATOR
+ /// ```
+ /// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createoperator.html)
+ CreateOperator(CreateOperator),
+ /// ```sql
+ /// CREATE OPERATOR FAMILY
+ /// ```
+ /// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createopfamily.html)
+ CreateOperatorFamily(CreateOperatorFamily),
+ /// ```sql
+ /// CREATE OPERATOR CLASS
+ /// ```
+ /// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createopclass.html)
+ CreateOperatorClass(CreateOperatorClass),
+ /// ```sql
/// CREATE ROLE
/// ```
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createrole.html)
@@ -4817,6 +4834,11 @@ impl fmt::Display for Statement {
Ok(())
}
Statement::CreateIndex(create_index) => create_index.fmt(f),
+ Statement::CreateOperator(create_operator) => create_operator.fmt(f),
+ Statement::CreateOperatorFamily(create_operator_family) =>
+ create_operator_family.fmt(f),
+ Statement::CreateOperatorClass(create_operator_class) =>
+ create_operator_class.fmt(f),
Statement::CreateExtension(create_extension) => write!(f, "{create_extension}"),
Statement::DropExtension(drop_extension) => write!(f, "{drop_extension}"),
Statement::CreateRole(create_role) => write!(f, "{create_role}"),
diff --git a/tmp/agent-patch-flux-pr-2096.1-of-1.2026-02-28__18-27-22__gpt-5-1-codex-mini/app/src/parser/mod.rs b/app/src/parser/mod.rs
index 1ab4626..32f46a6 100644
--- a/tmp/agent-patch-flux-pr-2096.1-of-1.2026-02-28__18-27-22__gpt-5-1-codex-mini/app/src/parser/mod.rs
+++ b/app/src/parser/mod.rs
@@ -4776,6 +4776,14 @@ impl<'a> Parser<'a> {
self.parse_create_index(false)
} else if self.parse_keywords(&[Keyword::UNIQUE, Keyword::INDEX]) {
self.parse_create_index(true)
+ } else if self.parse_keyword(Keyword::OPERATOR) {
+ if self.parse_keyword(Keyword::FAMILY) {
+ self.parse_create_operator_family()
+ } else if self.parse_keyword(Keyword::CLASS) {
+ self.parse_create_operator_class()
+ } else {
+ self.parse_create_operator()
+ }
} else if self.parse_keyword(Keyword::VIRTUAL) {
self.parse_create_virtual_table()
} else if self.parse_keyword(Keyword::SCHEMA) {
@@ -6436,6 +6444,227 @@ impl<'a> Parser<'a> {
}))
}
+ pub fn parse_create_operator(&mut self) -> Result<Statement, ParserError> {
+ let name = self.parse_object_name(false)?;
+ self.expect_token(&Token::LParen)?;
+ let mut function_name: Option<ObjectName> = None;
+ let mut procedure_keyword = false;
+ let mut left_arg = None;
+ let mut right_arg = None;
+ let mut commutator = None;
+ let mut negator = None;
+ let mut restrict = None;
+ let mut join = None;
+ let mut hashes = false;
+ let mut merges = false;
+
+ loop {
+ if self.consume_token(&Token::RParen) {
+ break;
+ }
+ if self.parse_keyword(Keyword::FUNCTION) {
+ self.expect_token(&Token::Eq)?;
+ function_name = Some(self.parse_object_name(false)?);
+ procedure_keyword = false;
+ } else if self.parse_keyword(Keyword::PROCEDURE) {
+ self.expect_token(&Token::Eq)?;
+ function_name = Some(self.parse_object_name(false)?);
+ procedure_keyword = true;
+ } else if self.parse_keyword(Keyword::LEFTARG) {
+ self.expect_token(&Token::Eq)?;
+ left_arg = Some(self.parse_data_type()?);
+ } else if self.parse_keyword(Keyword::RIGHTARG) {
+ self.expect_token(&Token::Eq)?;
+ right_arg = Some(self.parse_data_type()?);
+ } else if self.parse_keyword(Keyword::COMMUTATOR) {
+ self.expect_token(&Token::Eq)?;
+ commutator = Some(self.parse_postgres_operator_name()?);
+ } else if self.parse_keyword(Keyword::NEGATOR) {
+ self.expect_token(&Token::Eq)?;
+ negator = Some(self.parse_postgres_operator_name()?);
+ } else if self.parse_keyword(Keyword::RESTRICT) {
+ self.expect_token(&Token::Eq)?;
+ restrict = Some(self.parse_object_name(false)?);
+ } else if self.parse_keyword(Keyword::JOIN) {
+ self.expect_token(&Token::Eq)?;
+ join = Some(self.parse_object_name(false)?);
+ } else if self.parse_keyword(Keyword::HASHES) {
+ hashes = true;
+ } else if self.parse_keyword(Keyword::MERGES) {
+ merges = true;
+ } else {
+ return self.expected("operator option", self.peek_token());
+ }
+
+ if self.consume_token(&Token::Comma) {
+ continue;
+ }
+ self.expect_token(&Token::RParen)?;
+ break;
+ }
+
+ if function_name.is_none() {
+ return self.expected("FUNCTION or PROCEDURE clause", self.peek_token());
+ }
+
+ Ok(Statement::CreateOperator(CreateOperator {
+ name,
+ function_name: function_name.unwrap(),
+ procedure_keyword,
+ left_arg,
+ right_arg,
+ commutator,
+ negator,
+ restrict,
+ join,
+ hashes,
+ merges,
+ }))
+ }
+
+ pub fn parse_create_operator_family(&mut self) -> Result<Statement, ParserError> {
+ let name = self.parse_object_name(false)?;
+ self.expect_keyword(Keyword::USING)?;
+ let using = self.parse_identifier()?;
+ Ok(Statement::CreateOperatorFamily(CreateOperatorFamily { name, using }))
+ }
+
+ pub fn parse_create_operator_class(&mut self) -> Result<Statement, ParserError> {
+ let name = self.parse_object_name(false)?;
+ let is_default = self.parse_keyword(Keyword::DEFAULT);
+ self.expect_keywords(&[Keyword::FOR, Keyword::TYPE])?;
+ let data_type = self.parse_data_type()?;
+ self.expect_keyword(Keyword::USING)?;
+ let using = self.parse_identifier()?;
+ let family = if self.parse_keyword(Keyword::FAMILY) {
+ Some(self.parse_object_name(false)?)
+ } else {
+ None
+ };
+ self.expect_keyword(Keyword::AS)?;
+ let mut items = Vec::new();
+ loop {
+ items.push(self.parse_operator_class_item()?);
+ if !self.consume_token(&Token::Comma) {
+ break;
+ }
+ }
+ if items.is_empty() {
+ return self.expected("operator class item", self.peek_token());
+ }
+ Ok(Statement::CreateOperatorClass(CreateOperatorClass {
+ name,
+ is_default,
+ data_type,
+ using,
+ family,
+ items,
+ }))
+ }
+
+ fn parse_operator_class_item(&mut self) -> Result<OperatorClassItem, ParserError> {
+ if self.parse_keyword(Keyword::OPERATOR) {
+ let strategy_number = self.parse_literal_uint()?;
+ let operator_name = self.parse_postgres_operator_name()?;
+ let op_types = if self.consume_token(&Token::LParen) {
+ let types = self.parse_operator_class_op_types()?;
+ self.expect_token(&Token::RParen)?;
+ Some(types)
+ } else {
+ None
+ };
+ let sort = self.parse_operator_class_sort()?;
+ Ok(OperatorClassItem::Operator {
+ strategy_number,
+ operator_name,
+ op_types,
+ sort,
+ })
+ } else if self.parse_keyword(Keyword::FUNCTION) {
+ let support_number = self.parse_literal_uint()?;
+ let op_types = if self.consume_token(&Token::LParen) {
+ let types = self.parse_operator_class_op_types()?;
+ self.expect_token(&Token::RParen)?;
+ Some(types)
+ } else {
+ None
+ };
+ let function_name = self.parse_object_name(false)?;
+ self.expect_token(&Token::LParen)?;
+ let arguments = self.parse_comma_separated(Parser::parse_data_type)?;
+ self.expect_token(&Token::RParen)?;
+ Ok(OperatorClassItem::Function {
+ support_number,
+ op_types,
+ function_name,
+ arguments,
+ })
+ } else if self.parse_keyword(Keyword::STORAGE) {
+ let storage_type = self.parse_data_type()?;
+ Ok(OperatorClassItem::Storage { storage_type })
+ } else {
+ self.expected("OPERATOR, FUNCTION, or STORAGE", self.peek_token())
+ }
+ }
+
+ fn parse_operator_class_sort(&mut self) -> Result<Option<OperatorClassSort>, ParserError> {
+ if self.parse_keyword(Keyword::FOR) {
+ if self.parse_keyword(Keyword::SEARCH) {
+ Ok(Some(OperatorClassSort::Search))
+ } else if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) {
+ let sort_family = self.parse_object_name(false)?;
+ Ok(Some(OperatorClassSort::OrderBy(sort_family)))
+ } else {
+ self.expected("SEARCH or ORDER BY after FOR", self.peek_token())
+ }
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn parse_operator_class_op_types(&mut self) -> Result<Vec<OperatorClassOpType>, ParserError> {
+ let mut types = Vec::new();
+ loop {
+ if self.parse_keyword(Keyword::NONE) {
+ types.push(OperatorClassOpType::None);
+ } else {
+ types.push(OperatorClassOpType::DataType(self.parse_data_type()?));
+ }
+ if !self.consume_token(&Token::Comma) {
+ break;
+ }
+ }
+ Ok(types)
+ }
+
+ fn parse_postgres_operator_name(&mut self) -> Result<PgOperator, ParserError> {
+ if self.parse_keyword(Keyword::OPERATOR) {
+ self.expect_token(&Token::LParen)?;
+ let names = self.parse_postgres_operator_parts()?;
+ self.expect_token(&Token::RParen)?;
+ return Ok(PgOperator { names });
+ }
+ Ok(PgOperator {
+ names: self.parse_postgres_operator_parts()?,
+ })
+ }
+
+ fn parse_postgres_operator_parts(&mut self) -> Result<Vec<String>, ParserError> {
+ let mut names = Vec::new();
+ loop {
+ self.advance_token();
+ names.push(self.get_current_token().to_string());
+ if !self.consume_token(&Token::Period) {
+ break;
+ }
+ }
+ if names.is_empty() {
+ self.expected("operator name", self.peek_token())
+ } else {
+ Ok(names)
+ }
+ }
+
pub fn parse_drop(&mut self) -> Result<Statement, ParserError> {
// MySQL dialect supports `TEMPORARY`
let temporary = dialect_of!(self is MySqlDialect | GenericDialect | DuckDbDialect)
diff --git a/tmp/agent-patch-flux-pr-2096.1-of-1.2026-02-28__18-27-22__gpt-5-1-codex-mini/app/tests/sqlparser_postgres.rs b/app/tests/sqlparser_postgres.rs
index 3bdf6d1..6dac727 100644
--- a/tmp/agent-patch-flux-pr-2096.1-of-1.2026-02-28__18-27-22__gpt-5-1-codex-mini/app/tests/sqlparser_postgres.rs
+++ b/app/tests/sqlparser_postgres.rs
@@ -3563,6 +3563,47 @@ fn parse_on_commit() {
pg_and_generic().verified_stmt("CREATE TEMPORARY TABLE table (COL INT) ON COMMIT DROP");
}
+#[test]
+fn parse_create_operator_statements() {
+ let sql = r#"CREATE OPERATOR === (
+ FUNCTION = area_equal_function,
+ LEFTARG = box,
+ RIGHTARG = box,
+ COMMUTATOR = OPERATOR(pg_catalog.===),
+ NEGATOR = OPERATOR(pg_catalog.!==),
+ RESTRICT = area_restriction_function,
+ JOIN = area_join_function,
+ HASHES,
+ MERGES
+ )"#;
+ let canonical = "CREATE OPERATOR === (FUNCTION = area_equal_function, LEFTARG = box, RIGHTARG = box, COMMUTATOR = OPERATOR(pg_catalog.===), NEGATOR = OPERATOR(pg_catalog.!==), RESTRICT = area_restriction_function, JOIN = area_join_function, HASHES, MERGES)";
+ pg().one_statement_parses_to(sql, canonical);
+}
+
+#[test]
+fn parse_create_operator_family_and_class() {
+ pg().one_statement_parses_to(
+ "CREATE OPERATOR FAMILY gist_ops USING gist",
+ "CREATE OPERATOR FAMILY gist_ops USING gist",
+ );
+ let sql = r#"CREATE OPERATOR CLASS gist__int_ops DEFAULT FOR TYPE _int4 USING gist FAMILY foo AS
+ OPERATOR 3 &&,
+ OPERATOR 6 = (anyarray, anyarray),
+ OPERATOR 7 @>,
+ OPERATOR 8 <@,
+ OPERATOR 20 @@ (_int4, query_int),
+ FUNCTION 1 g_int_consistent (internal, _int4, smallint, oid, internal),
+ FUNCTION 2 g_int_union (internal, internal),
+ FUNCTION 3 g_int_compress (internal),
+ FUNCTION 4 g_int_decompress (internal),
+ FUNCTION 5 g_int_penalty (internal, internal, internal),
+ FUNCTION 6 g_int_picksplit (internal, internal),
+ FUNCTION 7 g_int_same (_int4, _int4, internal),
+ STORAGE internal"#;
+ let canonical = "CREATE OPERATOR CLASS gist__int_ops DEFAULT FOR TYPE _int4 USING gist FAMILY foo AS OPERATOR 3 OPERATOR(&&), OPERATOR 6 OPERATOR(=) (anyarray, anyarray), OPERATOR 7 OPERATOR(@>), OPERATOR 8 OPERATOR(<@), OPERATOR 20 OPERATOR(@@) (_int4, query_int), FUNCTION 1 g_int_consistent (internal, _int4, smallint, oid, internal), FUNCTION 2 g_int_union (internal, internal), FUNCTION 3 g_int_compress (internal), FUNCTION 4 g_int_decompress (internal), FUNCTION 5 g_int_penalty (internal, internal, internal), FUNCTION 6 g_int_picksplit (internal, internal), FUNCTION 7 g_int_same (_int4, _int4, internal), STORAGE internal";
+ pg().one_statement_parses_to(sql, canonical);
+}
+
fn pg() -> TestedDialects {
TestedDialects::new(vec![Box::new(PostgreSqlDialect {})])
}