add support for postgres composite types (#466)

* add support for postgres composite types

Signed-off-by: password <rbalajis25@gmail.com>

* fix composite test for bigdecimal feature

Signed-off-by: password <rbalajis25@gmail.com>
This commit is contained in:
Poonai 2022-05-10 00:42:22 +05:30 committed by GitHub
parent 6b2fc8102f
commit ed86c6d53d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 1 deletions

View file

@ -231,6 +231,11 @@ pub enum Expr {
operator: JsonOperator,
right: Box<Expr>,
},
/// CompositeAccess (postgres) eg: SELECT (information_schema._pg_expandarray(array['i','i'])).n
CompositeAccess {
expr: Box<Expr>,
key: Ident,
},
/// `IS NULL` operator
IsNull(Box<Expr>),
/// `IS NOT NULL` operator
@ -565,6 +570,9 @@ impl fmt::Display for Expr {
} => {
write!(f, "{} {} {}", left, operator, right)
}
Expr::CompositeAccess { expr, key } => {
write!(f, "{}.{}", expr, key)
}
}
}
}

View file

@ -518,7 +518,18 @@ impl<'a> Parser<'a> {
}
};
self.expect_token(&Token::RParen)?;
Ok(expr)
if !self.consume_token(&Token::Period) {
return Ok(expr);
}
let tok = self.next_token();
let key = match tok {
Token::Word(word) => word.to_ident(),
_ => return parser_err!(format!("Expected identifier, found: {}", tok)),
};
Ok(Expr::CompositeAccess {
expr: Box::new(expr),
key,
})
}
Token::Placeholder(_) => {
self.prev_token();

View file

@ -1334,6 +1334,67 @@ fn test_json() {
);
}
#[test]
fn test_composite_value() {
let sql = "SELECT (on_hand.item).name FROM on_hand WHERE (on_hand.item).price > 9";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::CompositeAccess {
key: Ident::new("name"),
expr: Box::new(Expr::Nested(Box::new(Expr::CompoundIdentifier(vec![
Ident::new("on_hand"),
Ident::new("item")
]))))
}),
select.projection[0]
);
#[cfg(feature = "bigdecimal")]
let num: Expr = Expr::Value(Value::Number(bigdecimal::BigDecimal::from(9), false));
#[cfg(not(feature = "bigdecimal"))]
let num: Expr = Expr::Value(Value::Number("9".to_string(), false));
assert_eq!(
select.selection,
Some(Expr::BinaryOp {
left: Box::new(Expr::CompositeAccess {
key: Ident::new("price"),
expr: Box::new(Expr::Nested(Box::new(Expr::CompoundIdentifier(vec![
Ident::new("on_hand"),
Ident::new("item")
]))))
}),
op: BinaryOperator::Gt,
right: Box::new(num)
})
);
let sql = "SELECT (information_schema._pg_expandarray(ARRAY['i', 'i'])).n";
let select = pg().verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::CompositeAccess {
key: Ident::new("n"),
expr: Box::new(Expr::Nested(Box::new(Expr::Function(Function {
name: ObjectName(vec![
Ident::new("information_schema"),
Ident::new("_pg_expandarray")
]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Array(
Array {
elem: vec![
Expr::Value(Value::SingleQuotedString("i".to_string())),
Expr::Value(Value::SingleQuotedString("i".to_string())),
],
named: true
}
)))],
over: None,
distinct: false,
}))))
}),
select.projection[0]
);
}
#[test]
fn parse_comments() {
match pg().verified_stmt("COMMENT ON COLUMN tab.name IS 'comment'") {