use crate::ast::*;
use crate::str::ext::*;
use crate::str::helpers::*;
use crate::str::{Context, SqlBuilder, SqlBuilderWithContext, SqlError};
impl SqlBuilder for A_ArrayExpr {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let elements = must!(self.elements);
buffer.push_str("ARRAY[");
ExprList(elements).build(buffer)?;
buffer.push(']');
Ok(())
}
}
impl SqlBuilder for &Option<ConstValue> {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if let Some(value) = self {
(*value).build(buffer)
} else {
Ok(())
}
}
}
impl SqlBuilder for ConstValue {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
SqlConstValue(self).build_with_context(buffer, Context::Constant)
}
}
impl SqlBuilderWithContext for ConstValue {
fn build_with_context(&self, buffer: &mut String, context: Context) -> Result<(), SqlError> {
SqlConstValue(self).build_with_context(buffer, context)
}
}
impl SqlBuilderWithContext for A_Expr {
fn build_with_context(&self, buffer: &mut String, context: Context) -> Result<(), SqlError> {
fn need_parenthesis(expr: &Option<Box<Node>>) -> bool {
match expr {
Some(node) => matches!(
**node,
Node::BoolExpr(_) | Node::NullTest(_) | Node::A_Expr(_)
),
None => false,
}
}
let need_left_parens = need_parenthesis(&self.lexpr);
let need_right_parens = need_parenthesis(&self.rexpr);
match *self.kind {
A_Expr_Kind::AEXPR_OP => {
let need_outer_parens = context == Context::AExpr;
if need_outer_parens {
buffer.push('(');
}
if let Some(ref left) = self.lexpr {
if need_left_parens {
buffer.push('(');
}
Expr(left).build(buffer)?;
if need_left_parens {
buffer.push(')');
}
buffer.push(' ');
}
let name = must!(self.name);
QualifiedOperator(name).build(buffer)?;
if let Some(ref right) = self.rexpr {
buffer.push(' ');
if need_right_parens {
buffer.push('(');
}
Expr(right).build(buffer)?;
if need_right_parens {
buffer.push(')');
}
}
if need_outer_parens {
buffer.push(')');
}
}
A_Expr_Kind::AEXPR_OP_ANY | A_Expr_Kind::AEXPR_OP_ALL => {
let left = must!(self.lexpr);
let right = must!(self.rexpr);
let name = must!(self.name);
Expr(left).build(buffer)?;
buffer.push(' ');
SubqueryOperator(name).build(buffer)?;
if (*self.kind).eq(&A_Expr_Kind::AEXPR_OP_ALL) {
buffer.push_str(" ALL(");
} else {
buffer.push_str(" ANY(");
}
Expr(right).build(buffer)?;
buffer.push(')');
}
A_Expr_Kind::AEXPR_DISTINCT => {
let left = must!(self.lexpr);
let right = must!(self.rexpr);
if need_left_parens {
buffer.push('(');
}
Expr(left).build(buffer)?;
if need_left_parens {
buffer.push(')');
}
buffer.push_str(" IS DISTINCT FROM ");
if need_right_parens {
buffer.push('(');
}
Expr(right).build(buffer)?;
if need_right_parens {
buffer.push(')');
}
}
A_Expr_Kind::AEXPR_NOT_DISTINCT => {
let left = must!(self.lexpr);
let right = must!(self.rexpr);
Expr(left).build(buffer)?;
buffer.push_str(" IS NOT DISTINCT FROM ");
Expr(right).build(buffer)?;
}
A_Expr_Kind::AEXPR_NULLIF => {
let left = must!(self.lexpr);
let right = must!(self.rexpr);
let name = must!(self.name);
let name = node_vec_to_string_vec(name);
if name.len() != 1 {
return Err(SqlError::Unsupported("name.len() != 1".into()));
}
let name = name[0];
if name.ne("=") {
return Err(SqlError::Unsupported("name != '='".into()));
}
buffer.push_str("NULLIF(");
Expr(left).build(buffer)?;
buffer.push_str(", ");
Expr(right).build(buffer)?;
buffer.push(')');
}
A_Expr_Kind::AEXPR_IN => {
let left = must!(self.lexpr);
let right = must!(self.rexpr);
let name = must!(self.name);
let name = node_vec_to_string_vec(name);
if name.len() != 1 {
return Err(SqlError::Unsupported("name.len() != 1".into()));
}
let name = name[0];
Expr(left).build(buffer)?;
buffer.push(' ');
match &name[..] {
"=" => buffer.push_str("IN "),
"<>" => buffer.push_str("NOT IN "),
unsupported => {
return Err(SqlError::Unsupported(format!(
"Unsupported operator: {}",
unsupported
)));
}
}
buffer.push('(');
match &**right {
Node::SubLink(link) => link.build(buffer)?,
Node::List(list) => ExprList(&list.items).build(buffer)?,
other => return Err(SqlError::UnexpectedNodeType(other.name())),
}
buffer.push(')');
}
A_Expr_Kind::AEXPR_LIKE | A_Expr_Kind::AEXPR_ILIKE => {
let ilike = (*self.kind).eq(&A_Expr_Kind::AEXPR_ILIKE);
let left = must!(self.lexpr);
let right = must!(self.rexpr);
Expr(left).build(buffer)?;
buffer.push(' ');
let name = must!(self.name);
if name.len() != 1 {
return Err(SqlError::Unsupported("name.len() != 1".into()));
}
let name = string_value!(name[0]);
match &name[..] {
"~~" if !ilike => buffer.push_str("LIKE "),
"~~*" if ilike => buffer.push_str("ILIKE "),
"!~~" if !ilike => buffer.push_str("NOT LIKE "),
"!~~*" if ilike => buffer.push_str("NOT ILIKE "),
op => {
return Err(SqlError::Unsupported(format!(
"Unsupported operator: {}",
op
)));
}
}
Expr(right).build(buffer)?;
}
A_Expr_Kind::AEXPR_SIMILAR => {
let left = must!(self.lexpr);
let right = must!(self.rexpr);
let right = node!(**right, Node::FuncCall);
let name = must!(self.name);
if name.is_empty() {
return Err(SqlError::Unsupported("Empty name for AEXPR_OF".into()));
}
let name = string_value!(name[0]);
Expr(left).build(buffer)?;
if name.eq("~") {
buffer.push_str(" SIMILAR TO ");
} else if name.eq("!~") {
buffer.push_str(" NOT SIMILAR TO ");
} else {
return Err(SqlError::Unsupported(format!(
"Unexpected operator for AEXPR_SIMILAR: {}",
name
)));
}
let func_name = must!(right.funcname);
let func_name = node_vec_to_string_vec(func_name);
if func_name.len() != 2 {
return Err(SqlError::Unsupported(format!(
"Invalid func_name for AEXPR_SIMILAR: {:?}",
func_name
)));
}
if func_name[0].ne("pg_catalog") || func_name[1].ne("similar_to_escape") {
return Err(SqlError::Unsupported(format!(
"Invalid func_name for AEXPR_SIMILAR: {:?}",
func_name
)));
}
let args = must!(right.args);
if args.is_empty() || args.len() > 2 {
return Err(SqlError::Unsupported(format!(
"Invalid func args for AEXPR_SIMILAR: {}",
args.len()
)));
}
let mut args = args.iter();
Expr(args.next().unwrap()).build(buffer)?;
if let Some(arg) = args.next() {
buffer.push_str(" ESCAPE ");
Expr(arg).build(buffer)?;
}
}
A_Expr_Kind::AEXPR_BETWEEN
| A_Expr_Kind::AEXPR_NOT_BETWEEN
| A_Expr_Kind::AEXPR_BETWEEN_SYM
| A_Expr_Kind::AEXPR_NOT_BETWEEN_SYM => {
let left = must!(self.lexpr);
let right = must!(self.rexpr);
let right = node!(**right, Node::List);
let name = must!(self.name);
let name = node_vec_to_string_vec(name);
if name.len() != 1 {
return Err(SqlError::Unsupported("name.len() != 1".into()));
}
let name = name[0];
Expr(left).build(buffer)?;
buffer.push_str(&format!(" {} ", name));
let mut iter = right.items.iter().peekable();
while let Some(expr) = iter.next() {
Expr(expr).build(buffer)?;
if iter.peek().is_some() {
buffer.push_str(" AND ");
}
}
}
}
Ok(())
}
}
impl SqlBuilder for A_Indices {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push('[');
if let Some(ref index) = self.lidx {
Expr(index).build(buffer)?;
}
if self.is_slice {
buffer.push(':');
}
if let Some(ref index) = self.uidx {
Expr(index).build(buffer)?;
}
buffer.push(']');
Ok(())
}
}
impl SqlBuilder for A_Indirection {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let arg = must!(self.arg);
let empty = Vec::new();
let indirection = self.indirection.as_ref().unwrap_or(&empty);
let indirection_indices = if !indirection.is_empty() {
matches!(indirection[0], Node::A_Indices(_))
} else {
false
};
let parenthesis = matches!(
**arg,
Node::A_Indirection(_)
| Node::FuncCall(_)
| Node::A_Expr(_)
| Node::TypeCast(_)
| Node::RowExpr(_)
) || (matches!(**arg, Node::ColumnRef(_)) && !indirection_indices);
if parenthesis {
buffer.push('(');
}
Expr(arg).build(buffer)?;
if parenthesis {
buffer.push(')');
}
Indirection(indirection, 0).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for A_Star {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push('*');
Ok(())
}
}
impl SqlBuilder for AccessPriv {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if let Some(ref name) = self.priv_name {
match &name[..] {
"select" | "references" | "create" => buffer.push_str(name),
other => buffer.push_str("e_identifier(other)),
}
} else {
buffer.push_str("ALL");
}
if let Some(ref cols) = self.cols {
if !cols.is_empty() {
buffer.push_str(" (");
ColumnList(cols).build(buffer)?;
buffer.push(')');
}
}
Ok(())
}
}
impl SqlBuilder for AlterSystemStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let stmt = must!(self.setstmt);
buffer.push_str("ALTER SYSTEM ");
(**stmt).build(buffer)?;
Ok(())
}
}
impl SqlBuilderWithContext for AlterTableCmd {
fn build_with_context(&self, buffer: &mut String, context: Context) -> Result<(), SqlError> {
let mut options = None;
let mut trailing_missing_ok = false;
match *self.subtype {
AlterTableType::AT_AddColumn => {
if context == Context::AlterType {
buffer.push_str("ADD ATTRIBUTE");
} else {
buffer.push_str("ADD COLUMN");
}
}
AlterTableType::AT_AddColumnToView => unsupported!(self.subtype),
AlterTableType::AT_ColumnDefault => {
buffer.push_str("ALTER COLUMN");
if self.def.is_some() {
options = Some("SET DEFAULT");
} else {
options = Some("DROP DEFAULT");
}
}
AlterTableType::AT_CookedColumnDefault => unsupported!(self.subtype),
AlterTableType::AT_DropNotNull => {
buffer.push_str("ALTER COLUMN");
options = Some("DROP NOT NULL");
}
AlterTableType::AT_SetNotNull => {
buffer.push_str("ALTER COLUMN");
options = Some("SET NOT NULL");
}
AlterTableType::AT_DropExpression => {
buffer.push_str("ALTER COLUMN");
options = Some("DROP EXPRESSION");
trailing_missing_ok = true;
}
AlterTableType::AT_CheckNotNull => unsupported!(self.subtype),
AlterTableType::AT_SetStatistics => {
buffer.push_str("ALTER COLUMN");
options = Some("SET STATISTICS");
}
AlterTableType::AT_SetOptions => {
buffer.push_str("ALTER COLUMN");
options = Some("SET");
}
AlterTableType::AT_ResetOptions => {
buffer.push_str("ALTER COLUMN");
options = Some("RESET");
}
AlterTableType::AT_SetStorage => {
buffer.push_str("ALTER COLUMN");
options = Some("SET STORAGE");
}
AlterTableType::AT_DropColumn => {
if context == Context::AlterType {
buffer.push_str("DROP ATTRIBUTE");
} else {
buffer.push_str("DROP COLUMN");
}
}
AlterTableType::AT_AddIndex => buffer.push_str("ADD INDEX"),
AlterTableType::AT_ReAddIndex => unsupported!(self.subtype),
AlterTableType::AT_AddConstraint => buffer.push_str("ADD"),
AlterTableType::AT_ReAddConstraint => unsupported!(self.subtype),
AlterTableType::AT_ReAddDomainConstraint => unsupported!(self.subtype),
AlterTableType::AT_AlterConstraint => buffer.push_str("ALTER"),
AlterTableType::AT_ValidateConstraint => buffer.push_str("VALIDATE CONSTRAINT"),
AlterTableType::AT_AddIndexConstraint => unsupported!(self.subtype),
AlterTableType::AT_DropConstraint => buffer.push_str("DROP CONSTRAINT"),
AlterTableType::AT_ReAddComment => unsupported!(self.subtype),
AlterTableType::AT_AlterColumnType => {
if context == Context::AlterType {
buffer.push_str("ALTER ATTRIBUTE");
} else {
buffer.push_str("ALTER COLUMN");
}
options = Some("TYPE");
}
AlterTableType::AT_AlterColumnGenericOptions => buffer.push_str("ALTER COLUMN"),
AlterTableType::AT_ChangeOwner => {
buffer.push_str("OWNER TO ");
must!(self.newowner).build(buffer)?;
}
AlterTableType::AT_ClusterOn => buffer.push_str("CLUSTER ON"),
AlterTableType::AT_DropCluster => buffer.push_str("SET WITHOUT CLUSTER"),
AlterTableType::AT_SetLogged => buffer.push_str("SET LOGGED"),
AlterTableType::AT_SetUnLogged => buffer.push_str("SET UNLOGGED"),
AlterTableType::AT_DropOids => buffer.push_str("SET WITHOUT OIDS"),
AlterTableType::AT_SetTableSpace => buffer.push_str("SET TABLESPACE"),
AlterTableType::AT_SetRelOptions => buffer.push_str("SET"),
AlterTableType::AT_ResetRelOptions => buffer.push_str("RESET"),
AlterTableType::AT_ReplaceRelOptions => unsupported!(self.subtype),
AlterTableType::AT_EnableTrig => buffer.push_str("ENABLE TRIGGER"),
AlterTableType::AT_EnableAlwaysTrig => buffer.push_str("ENABLE ALWAYS TRIGGER"),
AlterTableType::AT_EnableReplicaTrig => buffer.push_str("ENABLE REPLICA TRIGGER"),
AlterTableType::AT_DisableTrig => buffer.push_str("DISABLE TRIGGER"),
AlterTableType::AT_EnableTrigAll => buffer.push_str("ENABLE TRIGGER"),
AlterTableType::AT_DisableTrigAll => buffer.push_str("DISABLE TRIGGER ALL"),
AlterTableType::AT_EnableTrigUser => buffer.push_str("ENABLE TRIGGER USER"),
AlterTableType::AT_DisableTrigUser => buffer.push_str("DISABLE TRIGGER USER"),
AlterTableType::AT_EnableRule => buffer.push_str("ENABLE RULE"),
AlterTableType::AT_EnableAlwaysRule => buffer.push_str("ENABLE ALWAYS RULE"),
AlterTableType::AT_EnableReplicaRule => buffer.push_str("ENABLE REPLICA RULE"),
AlterTableType::AT_DisableRule => buffer.push_str("DISABLE RULE"),
AlterTableType::AT_AddInherit => buffer.push_str("INHERIT"),
AlterTableType::AT_DropInherit => buffer.push_str("NO INHERIT"),
AlterTableType::AT_AddOf => buffer.push_str("OF"),
AlterTableType::AT_DropOf => buffer.push_str("NOT OF"),
AlterTableType::AT_ReplicaIdentity => buffer.push_str("REPLICA IDENTITY"),
AlterTableType::AT_EnableRowSecurity => buffer.push_str("ENABLE ROW LEVEL SECURITY"),
AlterTableType::AT_DisableRowSecurity => buffer.push_str("DISABLE ROW LEVEL SECURITY"),
AlterTableType::AT_ForceRowSecurity => buffer.push_str("FORCE ROW LEVEL SECURITY"),
AlterTableType::AT_NoForceRowSecurity => buffer.push_str("NO FORCE ROW LEVEL SECURITY"),
AlterTableType::AT_GenericOptions => {} AlterTableType::AT_AttachPartition => buffer.push_str("ATTACH PARTITION"),
AlterTableType::AT_DetachPartition | AlterTableType::AT_DetachPartitionFinalize => {
buffer.push_str("DETACH PARTITION")
}
AlterTableType::AT_AddIdentity => {
buffer.push_str("ALTER");
options = Some("ADD");
}
AlterTableType::AT_SetIdentity => buffer.push_str("ALTER"),
AlterTableType::AT_DropIdentity => {
buffer.push_str("ALTER COLUMN");
options = Some("DROP IDENTITY");
trailing_missing_ok = true;
}
AlterTableType::AT_SetCompression => {
buffer.push_str("ALTER COLUMN");
options = Some("SET COMPRESSION");
}
AlterTableType::AT_SetAccessMethod => {
buffer.push_str("SET ACCESS METHOD");
}
AlterTableType::AT_ReAddStatistics => unsupported!(self.subtype),
AlterTableType::AT_SetExpression => {
buffer.push_str("ALTER COLUMN");
options = Some("SET EXPRESSION AS");
}
}
if self.missing_ok && !trailing_missing_ok {
if *self.subtype == AlterTableType::AT_AddColumn {
buffer.push_str(" IF NOT EXISTS");
} else {
buffer.push_str(" IF EXISTS");
}
}
if let Some(ref name) = self.name {
buffer.push(' ');
buffer.push_str("e_identifier(name));
}
if self.num > 0 {
buffer.push_str(&format!(" {}", self.num));
}
if let Some(options) = options {
buffer.push(' ');
buffer.push_str(options);
}
if self.missing_ok && trailing_missing_ok {
buffer.push_str(" IF EXISTS");
}
match *self.subtype {
AlterTableType::AT_AttachPartition | AlterTableType::AT_DetachPartition => {
let def = must!(self.def);
let cmd = node!(**def, Node::PartitionCmd);
buffer.push(' ');
cmd.build(buffer)?;
}
AlterTableType::AT_DetachPartitionFinalize => {
let def = must!(self.def);
let cmd = node!(**def, Node::PartitionCmd);
buffer.push(' ');
cmd.build(buffer)?;
buffer.push_str(" FINALIZE");
}
AlterTableType::AT_AddColumn | AlterTableType::AT_AlterColumnType => {
let def = must!(self.def);
let column = node!(**def, Node::ColumnDef);
buffer.push(' ');
column.build(buffer)?;
}
AlterTableType::AT_ColumnDefault => {
if let Some(ref def) = self.def {
buffer.push(' ');
Expr(def).build(buffer)?;
}
}
AlterTableType::AT_SetStatistics => {
buffer.push(' ');
let def = must!(self.def);
SignedIConst(def).build(buffer)?;
}
AlterTableType::AT_SetOptions
| AlterTableType::AT_ResetOptions
| AlterTableType::AT_SetRelOptions
| AlterTableType::AT_ResetRelOptions => {
buffer.push(' ');
let def = must!(self.def);
let def = node!(**def, Node::List);
RelOptions(&def.items).build(buffer)?;
}
AlterTableType::AT_SetStorage => {
let def = must!(self.def);
let col_id = string_value!(**def);
buffer.push(' ');
ColId(col_id).build(buffer)?;
}
AlterTableType::AT_AddIdentity
| AlterTableType::AT_AddConstraint
| AlterTableType::AT_AlterConstraint => {
let def = must!(self.def);
let constraint = node!(**def, Node::Constraint);
buffer.push(' ');
constraint.build(buffer)?;
}
AlterTableType::AT_SetIdentity => {
let def = must!(self.def);
let list = node!(**def, Node::List);
buffer.push(' ');
AlterIdentityColumnOptionList(&list.items).build(buffer)?;
}
AlterTableType::AT_AlterColumnGenericOptions | AlterTableType::AT_GenericOptions => {
let def = must!(self.def);
let list = node!(**def, Node::List);
buffer.push(' ');
AlterGenericOptions(&list.items).build(buffer)?;
}
AlterTableType::AT_AddInherit | AlterTableType::AT_DropInherit => {
let def = must!(self.def);
let range = node!(**def, Node::RangeVar);
buffer.push(' ');
range.build_with_context(buffer, Context::None)?;
}
AlterTableType::AT_AddOf => {
let def = must!(self.def);
let type_name = node!(**def, Node::TypeName);
buffer.push(' ');
type_name.build(buffer)?;
}
AlterTableType::AT_ReplicaIdentity => {
let def = must!(self.def);
let stmt = node!(**def, Node::ReplicaIdentityStmt);
buffer.push(' ');
stmt.build(buffer)?;
}
AlterTableType::AT_SetCompression => {
let def = must!(self.def);
let ident = string_value!(**def);
buffer.push(' ');
buffer.push_str(quote_identifier(ident.as_str()).as_str());
}
AlterTableType::AT_SetExpression => {
let def = must!(self.def);
let expr = Expr(&*def);
buffer.push_str(" (");
expr.build(buffer)?;
buffer.push(')');
}
_ => {
if self.def.is_some() {
return Err(SqlError::Unsupported("Unsupported def".into()));
}
}
}
OptDropBehavior(&self.behavior).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for AlterDatabaseSetStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let dbname = must!(self.dbname);
let stmt = must!(self.setstmt);
buffer.push_str("ALTER DATABASE ");
ColId(dbname).build(buffer)?;
buffer.push(' ');
stmt.build(buffer)?;
Ok(())
}
}
impl SqlBuilder for AlterDatabaseStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let dbname = must!(self.dbname);
let options = must!(self.options);
buffer.push_str("ALTER DATABASE ");
ColId(dbname).build(buffer)?;
buffer.push(' ');
CreatedbOptList(options).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for AlterExtensionContentsStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.extname);
buffer.push_str("ALTER EXTENSION ");
ColId(name).build(buffer)?;
if self.action == 1 {
buffer.push_str(" ADD ");
} else if self.action == -1 {
buffer.push_str(" DROP ");
} else {
return Err(SqlError::Unsupported(format!(
"Unsupported action: {}",
self.action
)));
}
match *self.objtype {
ObjectType::OBJECT_ACCESS_METHOD => buffer.push_str("ACCESS METHOD "),
ObjectType::OBJECT_AGGREGATE => buffer.push_str("AGGREGATE "),
ObjectType::OBJECT_CAST => buffer.push_str("CAST "),
ObjectType::OBJECT_COLLATION => buffer.push_str("COLLATION "),
ObjectType::OBJECT_CONVERSION => buffer.push_str("CONVERSION "),
ObjectType::OBJECT_DOMAIN => buffer.push_str("DOMAIN "),
ObjectType::OBJECT_FUNCTION => buffer.push_str("FUNCTION "),
ObjectType::OBJECT_LANGUAGE => buffer.push_str("LANGUAGE "),
ObjectType::OBJECT_OPERATOR => buffer.push_str("OPERATOR "),
ObjectType::OBJECT_OPCLASS => buffer.push_str("OPERATOR CLASS "),
ObjectType::OBJECT_OPFAMILY => buffer.push_str("OPERATOR FAMILY "),
ObjectType::OBJECT_PROCEDURE => buffer.push_str("PROCEDURE "),
ObjectType::OBJECT_ROUTINE => buffer.push_str("ROUTINE "),
ObjectType::OBJECT_SCHEMA => buffer.push_str("SCHEMA "),
ObjectType::OBJECT_EVENT_TRIGGER => buffer.push_str("EVENT TRIGGER "),
ObjectType::OBJECT_TABLE => buffer.push_str("TABLE "),
ObjectType::OBJECT_TSPARSER => buffer.push_str("TEXT SEARCH PARSER "),
ObjectType::OBJECT_TSDICTIONARY => buffer.push_str("TEXT SEARCH DICTIONARY "),
ObjectType::OBJECT_TSTEMPLATE => buffer.push_str("TEXT SEARCH TEMPLATE "),
ObjectType::OBJECT_TSCONFIGURATION => buffer.push_str("TEXT SEARCH CONFIGURATION "),
ObjectType::OBJECT_SEQUENCE => buffer.push_str("SEQUENCE "),
ObjectType::OBJECT_VIEW => buffer.push_str("VIEW "),
ObjectType::OBJECT_MATVIEW => buffer.push_str("MATERIALIZED VIEW "),
ObjectType::OBJECT_FOREIGN_TABLE => buffer.push_str("FOREIGN TABLE "),
ObjectType::OBJECT_FDW => buffer.push_str("FOREIGN DATA WRAPPER "),
ObjectType::OBJECT_FOREIGN_SERVER => buffer.push_str("SERVER "),
ObjectType::OBJECT_TRANSFORM => buffer.push_str("TRANSFORM "),
ObjectType::OBJECT_TYPE => buffer.push_str("TYPE "),
unexpected => unsupported!(unexpected),
}
let object = must!(self.object);
match *self.objtype {
ObjectType::OBJECT_COLLATION
| ObjectType::OBJECT_CONVERSION
| ObjectType::OBJECT_TABLE
| ObjectType::OBJECT_TSPARSER
| ObjectType::OBJECT_TSDICTIONARY
| ObjectType::OBJECT_TSTEMPLATE
| ObjectType::OBJECT_TSCONFIGURATION
| ObjectType::OBJECT_SEQUENCE
| ObjectType::OBJECT_VIEW
| ObjectType::OBJECT_MATVIEW
| ObjectType::OBJECT_FOREIGN_TABLE => {
let list = node!(**object, Node::List);
AnyName(&list.items).build(buffer)?;
}
ObjectType::OBJECT_ACCESS_METHOD
| ObjectType::OBJECT_LANGUAGE
| ObjectType::OBJECT_SCHEMA
| ObjectType::OBJECT_EVENT_TRIGGER
| ObjectType::OBJECT_FDW
| ObjectType::OBJECT_FOREIGN_SERVER => {
let value = string_value!(**object);
ColId(value).build(buffer)?;
}
ObjectType::OBJECT_AGGREGATE => {
let arg = node!(**object, Node::ObjectWithArgs);
AggregateWithArgTypes(arg).build(buffer)?;
}
ObjectType::OBJECT_FUNCTION
| ObjectType::OBJECT_PROCEDURE
| ObjectType::OBJECT_ROUTINE => {
let arg = node!(**object, Node::ObjectWithArgs);
FunctionWithArgTypes(arg).build(buffer)?;
}
ObjectType::OBJECT_OPERATOR => {
let arg = node!(**object, Node::ObjectWithArgs);
OperatorWithArgTypes(arg).build(buffer)?;
}
ObjectType::OBJECT_CAST => {
let list = node!(**object, Node::List);
if list.items.len() != 2 {
return Err(SqlError::Unsupported(format!(
"Expected object len 2 for {:?}: {}",
self.objtype,
list.items.len()
)));
}
buffer.push('(');
node!(list.items[0], Node::TypeName).build(buffer)?;
buffer.push_str(" AS ");
node!(list.items[1], Node::TypeName).build(buffer)?;
buffer.push(')');
}
ObjectType::OBJECT_DOMAIN | ObjectType::OBJECT_TYPE => {
let type_name = node!(**object, Node::TypeName);
type_name.build(buffer)?;
}
ObjectType::OBJECT_OPFAMILY | ObjectType::OBJECT_OPCLASS => {
let list = node!(**object, Node::List);
if list.items.len() != 2 {
return Err(SqlError::Unsupported(format!(
"Expected object len 2 for {:?}: {}",
self.objtype,
list.items.len()
)));
}
AnyName(&list.items[1..]).build(buffer)?;
buffer.push_str(" USING ");
let val = string_value!(list.items[0]);
ColId(val).build(buffer)?;
}
ObjectType::OBJECT_TRANSFORM => {
let list = node!(**object, Node::List);
if list.items.len() != 2 {
return Err(SqlError::Unsupported(format!(
"Expected object len 2 for {:?}: {}",
self.objtype,
list.items.len()
)));
}
buffer.push_str("FOR ");
node!(list.items[0], Node::TypeName).build(buffer)?;
buffer.push_str(" LANGUAGE ");
ColId(string_value!(list.items[1])).build(buffer)?;
}
unexpected => unsupported!(unexpected),
}
Ok(())
}
}
impl SqlBuilder for AlterExtensionStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.extname);
buffer.push_str("ALTER EXTENSION ");
ColId(name).build(buffer)?;
buffer.push_str(" UPDATE");
if let Some(ref options) = self.options {
for opt in iter_only!(options, Node::DefElem) {
let opt_name = must!(opt.defname);
if opt_name.eq("new_version") {
let arg = must!(opt.arg);
buffer.push_str(" TO ");
NonReservedWordOrSconst(arg).build(buffer)?;
}
}
}
Ok(())
}
}
impl SqlBuilder for AlterObjectDependsStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let extname = must!(self.extname);
buffer.push_str("ALTER ");
match *self.object_type {
ObjectType::OBJECT_FUNCTION => {
let args = must!(self.object);
let args = node!(**args, Node::ObjectWithArgs);
buffer.push_str("FUNCTION ");
FunctionWithArgTypes(args).build(buffer)?;
}
ObjectType::OBJECT_PROCEDURE => {
let args = must!(self.object);
let args = node!(**args, Node::ObjectWithArgs);
buffer.push_str("PROCEDURE ");
FunctionWithArgTypes(args).build(buffer)?;
}
ObjectType::OBJECT_ROUTINE => {
let args = must!(self.object);
let args = node!(**args, Node::ObjectWithArgs);
buffer.push_str("ROUTINE ");
FunctionWithArgTypes(args).build(buffer)?;
}
ObjectType::OBJECT_TRIGGER => {
let list = must!(self.object);
let list = node!(**list, Node::List);
if list.items.is_empty() {
return Err(SqlError::Unsupported("Empty list".into()));
}
let relation = must!(self.relation);
buffer.push_str("TRIGGER ");
ColId(string_value!(list.items[0])).build(buffer)?;
buffer.push_str(" ON ");
(**relation).build_with_context(buffer, Context::None)?;
}
ObjectType::OBJECT_MATVIEW => {
let relation = must!(self.relation);
buffer.push_str("MATERIALIZED VIEW ");
(**relation).build_with_context(buffer, Context::None)?;
}
ObjectType::OBJECT_INDEX => {
let relation = must!(self.relation);
buffer.push_str("INDEX ");
(**relation).build_with_context(buffer, Context::None)?;
}
unexpected => unsupported!(unexpected),
}
if self.remove {
buffer.push_str(" NO");
}
buffer.push_str(" DEPENDS ON EXTENSION ");
ColId(extname).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for AlterObjectSchemaStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let relation = must!(self.relation);
let new_schema = must!(self.newschema);
buffer.push_str("ALTER");
match *self.object_type {
ObjectType::OBJECT_ACCESS_METHOD => buffer.push_str(" ACCESS METHOD"),
ObjectType::OBJECT_AGGREGATE => buffer.push_str(" AGGREGATE"),
ObjectType::OBJECT_CAST => buffer.push_str(" CAST"),
ObjectType::OBJECT_COLLATION => buffer.push_str(" COLLATION"),
ObjectType::OBJECT_CONVERSION => buffer.push_str(" CONVERSION"),
ObjectType::OBJECT_DOMAIN => buffer.push_str(" DOMAIN"),
ObjectType::OBJECT_EVENT_TRIGGER => buffer.push_str(" EVENT TRIGGER"),
ObjectType::OBJECT_EXTENSION => buffer.push_str(" EXTENSION"),
ObjectType::OBJECT_FDW => buffer.push_str(" FOREIGN DATA WRAPPER"),
ObjectType::OBJECT_FOREIGN_SERVER => buffer.push_str(" SERVER"),
ObjectType::OBJECT_FOREIGN_TABLE => buffer.push_str(" FOREIGN TABLE"),
ObjectType::OBJECT_FUNCTION => buffer.push_str(" FUNCTION"),
ObjectType::OBJECT_INDEX => buffer.push_str(" INDEX"),
ObjectType::OBJECT_LANGUAGE => buffer.push_str(" LANGUAGE"),
ObjectType::OBJECT_MATVIEW => buffer.push_str(" MATERIALIZED VIEW"),
ObjectType::OBJECT_OPCLASS => buffer.push_str(" OPERATOR CLASS"),
ObjectType::OBJECT_OPERATOR => buffer.push_str(" OPERATOR"),
ObjectType::OBJECT_OPFAMILY => buffer.push_str(" OPERATOR FAMILY"),
ObjectType::OBJECT_POLICY => buffer.push_str(" POLICY"),
ObjectType::OBJECT_PROCEDURE => buffer.push_str(" PROCEDURE"),
ObjectType::OBJECT_PUBLICATION => buffer.push_str(" PUBLICATION"),
ObjectType::OBJECT_ROUTINE => buffer.push_str(" ROUTINE"),
ObjectType::OBJECT_RULE => buffer.push_str(" RULE"),
ObjectType::OBJECT_SCHEMA => buffer.push_str(" SCHEMA"),
ObjectType::OBJECT_SEQUENCE => buffer.push_str(" SEQUENCE"),
ObjectType::OBJECT_STATISTIC_EXT => buffer.push_str(" STATISTICS"),
ObjectType::OBJECT_TABLE => buffer.push_str(" TABLE"),
ObjectType::OBJECT_TRANSFORM => buffer.push_str(" TRANSFORM"),
ObjectType::OBJECT_TRIGGER => buffer.push_str(" TRIGGER"),
ObjectType::OBJECT_TSCONFIGURATION => buffer.push_str(" TEXT SEARCH CONFIGURATION"),
ObjectType::OBJECT_TSDICTIONARY => buffer.push_str(" TEXT SEARCH DICTIONARY"),
ObjectType::OBJECT_TSPARSER => buffer.push_str(" TEXT SEARCH PARSER"),
ObjectType::OBJECT_TSTEMPLATE => buffer.push_str(" TEXT SEARCH TEMPLATE"),
ObjectType::OBJECT_TYPE => buffer.push_str(" TYPE"),
ObjectType::OBJECT_VIEW => buffer.push_str(" VIEW"),
unsupported => return Err(SqlError::Unsupported(format!("{:?}", unsupported))),
}
if self.missing_ok {
buffer.push_str(" IF EXISTS");
}
buffer.push(' ');
(**relation).build_with_context(buffer, Context::None)?;
buffer.push_str(" SET SCHEMA ");
buffer.push_str(new_schema);
Ok(())
}
}
impl SqlBuilder for AlterTableSpaceOptionsStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.tablespacename);
let options = must!(self.options);
buffer.push_str("ALTER TABLESPACE ");
ColId(name).build(buffer)?;
if self.is_reset {
buffer.push_str(" RESET ");
} else {
buffer.push_str(" SET ");
}
RelOptions(options).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for AlterTableStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let relation = must!(self.relation);
let commands = must!(self.cmds);
let mut context = Context::None;
buffer.push_str("ALTER");
match *self.objtype {
ObjectType::OBJECT_TABLE => buffer.push_str(" TABLE"),
ObjectType::OBJECT_FOREIGN_TABLE => buffer.push_str(" FOREIGN TABLE"),
ObjectType::OBJECT_INDEX => buffer.push_str(" INDEX"),
ObjectType::OBJECT_SEQUENCE => buffer.push_str(" SEQUENCE"),
ObjectType::OBJECT_VIEW => buffer.push_str(" VIEW"),
ObjectType::OBJECT_MATVIEW => buffer.push_str(" MATERIALIZED VIEW"),
ObjectType::OBJECT_TYPE => {
buffer.push_str(" TYPE");
context = Context::AlterType;
}
unexpected => return Err(SqlError::UnexpectedObjectType(unexpected)),
}
if self.missing_ok {
buffer.push_str(" IF EXISTS");
}
buffer.push(' ');
(**relation).build_with_context(buffer, context)?;
for (index, cmd) in iter_only!(commands, Node::AlterTableCmd).enumerate() {
if index == 0 {
buffer.push(' ');
} else {
buffer.push_str(", ");
}
cmd.build_with_context(buffer, context)?;
}
Ok(())
}
}
impl SqlBuilder for CollateClause {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.collname);
if let Some(ref arg) = self.arg {
let paren = matches!(**arg, Node::A_Expr(_));
if paren {
buffer.push('(');
}
Expr(arg).build(buffer)?;
if paren {
buffer.push(')');
}
buffer.push(' ');
}
buffer.push_str("COLLATE ");
AnyName(name).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for ColumnDef {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if let Some(ref name) = self.colname {
buffer.push_str(name);
}
if let Some(ref name) = self.type_name {
if !buffer.is_empty() && !buffer.ends_with(' ') {
buffer.push(' ');
}
(**name).build(buffer)?;
}
if let Some(ref raw) = self.raw_default {
buffer.push(' ');
buffer.push_str("USING ");
Expr(raw).build(buffer)?;
}
if let Some(ref fdw) = self.fdwoptions {
buffer.push(' ');
CreateGenericOptions(fdw).build(buffer)?;
}
if let Some(ref constraints) = self.constraints {
for constraint in iter_only!(constraints, Node::Constraint) {
buffer.push(' ');
constraint.build(buffer)?;
}
}
if let Some(ref clause) = self.coll_clause {
buffer.push(' ');
(**clause).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for ColumnRef {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let fields = must!(self.fields);
let mut iter = fields.iter();
if let Some(node) = iter.next() {
match node {
Node::A_Star(star) => star.build(buffer)?,
Node::String { sval: Some(value) } => buffer.push_str("e_identifier(value)),
_ => {}
}
} else {
return Err(SqlError::Missing("fields[0]".into()));
}
Indirection(fields, 1).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for CommentStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("COMMENT ON ");
match *self.objtype {
ObjectType::OBJECT_COLUMN => buffer.push_str("COLUMN "),
ObjectType::OBJECT_INDEX => buffer.push_str("INDEX "),
ObjectType::OBJECT_SEQUENCE => buffer.push_str("SEQUENCE "),
ObjectType::OBJECT_STATISTIC_EXT => buffer.push_str("STATISTICS "),
ObjectType::OBJECT_TABLE => buffer.push_str("TABLE "),
ObjectType::OBJECT_VIEW => buffer.push_str("VIEW "),
ObjectType::OBJECT_MATVIEW => buffer.push_str("MATERIALIZED VIEW "),
ObjectType::OBJECT_COLLATION => buffer.push_str("COLLATION "),
ObjectType::OBJECT_CONVERSION => buffer.push_str("CONVERSION "),
ObjectType::OBJECT_FOREIGN_TABLE => buffer.push_str("FOREIGN TABLE "),
ObjectType::OBJECT_TSCONFIGURATION => buffer.push_str("TEXT SEARCH CONFIGURATION "),
ObjectType::OBJECT_TSDICTIONARY => buffer.push_str("TEXT SEARCH DICTIONARY "),
ObjectType::OBJECT_TSPARSER => buffer.push_str("TEXT SEARCH PARSER "),
ObjectType::OBJECT_TSTEMPLATE => buffer.push_str("TEXT SEARCH TEMPLATE "),
ObjectType::OBJECT_ACCESS_METHOD => buffer.push_str("ACCESS METHOD "),
ObjectType::OBJECT_DATABASE => buffer.push_str("DATABASE "),
ObjectType::OBJECT_EVENT_TRIGGER => buffer.push_str("EVENT TRIGGER "),
ObjectType::OBJECT_EXTENSION => buffer.push_str("EXTENSION "),
ObjectType::OBJECT_FDW => buffer.push_str("FOREIGN DATA WRAPPER "),
ObjectType::OBJECT_LANGUAGE => buffer.push_str("LANGUAGE "),
ObjectType::OBJECT_PUBLICATION => buffer.push_str("PUBLICATION "),
ObjectType::OBJECT_ROLE => buffer.push_str("ROLE "),
ObjectType::OBJECT_SCHEMA => buffer.push_str("SCHEMA "),
ObjectType::OBJECT_FOREIGN_SERVER => buffer.push_str("SERVER "),
ObjectType::OBJECT_SUBSCRIPTION => buffer.push_str("SUBSCRIPTION "),
ObjectType::OBJECT_TABLESPACE => buffer.push_str("TABLESPACE "),
ObjectType::OBJECT_TYPE => buffer.push_str("TYPE "),
ObjectType::OBJECT_DOMAIN => buffer.push_str("DOMAIN "),
ObjectType::OBJECT_AGGREGATE => buffer.push_str("AGGREGATE "),
ObjectType::OBJECT_FUNCTION => buffer.push_str("FUNCTION "),
ObjectType::OBJECT_OPERATOR => buffer.push_str("OPERATOR "),
ObjectType::OBJECT_TABCONSTRAINT => buffer.push_str("CONSTRAINT "),
ObjectType::OBJECT_DOMCONSTRAINT => buffer.push_str("CONSTRAINT "),
ObjectType::OBJECT_POLICY => buffer.push_str("POLICY "),
ObjectType::OBJECT_PROCEDURE => buffer.push_str("PROCEDURE "),
ObjectType::OBJECT_ROUTINE => buffer.push_str("ROUTINE "),
ObjectType::OBJECT_RULE => buffer.push_str("RULE "),
ObjectType::OBJECT_TRANSFORM => buffer.push_str("TRANSFORM "),
ObjectType::OBJECT_TRIGGER => buffer.push_str("TRIGGER "),
ObjectType::OBJECT_OPCLASS => buffer.push_str("OPERATOR CLASS "),
ObjectType::OBJECT_OPFAMILY => buffer.push_str("OPERATOR FAMILY "),
ObjectType::OBJECT_LARGEOBJECT => buffer.push_str("LARGE OBJECT "),
ObjectType::OBJECT_CAST => buffer.push_str("CAST "),
unexpected => unsupported!(unexpected),
}
let object = must!(self.object);
match *self.objtype {
ObjectType::OBJECT_COLUMN
| ObjectType::OBJECT_INDEX
| ObjectType::OBJECT_SEQUENCE
| ObjectType::OBJECT_STATISTIC_EXT
| ObjectType::OBJECT_TABLE
| ObjectType::OBJECT_VIEW
| ObjectType::OBJECT_MATVIEW
| ObjectType::OBJECT_COLLATION
| ObjectType::OBJECT_CONVERSION
| ObjectType::OBJECT_FOREIGN_TABLE
| ObjectType::OBJECT_TSCONFIGURATION
| ObjectType::OBJECT_TSDICTIONARY
| ObjectType::OBJECT_TSPARSER
| ObjectType::OBJECT_TSTEMPLATE => {
let list = node!(**object, Node::List);
AnyName(&list.items).build(buffer)?;
}
ObjectType::OBJECT_ACCESS_METHOD
| ObjectType::OBJECT_DATABASE
| ObjectType::OBJECT_EVENT_TRIGGER
| ObjectType::OBJECT_EXTENSION
| ObjectType::OBJECT_FDW
| ObjectType::OBJECT_LANGUAGE
| ObjectType::OBJECT_PUBLICATION
| ObjectType::OBJECT_ROLE
| ObjectType::OBJECT_SCHEMA
| ObjectType::OBJECT_FOREIGN_SERVER
| ObjectType::OBJECT_SUBSCRIPTION
| ObjectType::OBJECT_TABLESPACE => {
let value = string_value!(**object);
buffer.push_str("e_identifier(value));
}
ObjectType::OBJECT_TYPE | ObjectType::OBJECT_DOMAIN => {
let type_name = node!(**object, Node::TypeName);
type_name.build(buffer)?;
}
ObjectType::OBJECT_AGGREGATE => {
let owa = node!(**object, Node::ObjectWithArgs);
AggregateWithArgTypes(owa).build(buffer)?;
}
ObjectType::OBJECT_FUNCTION
| ObjectType::OBJECT_PROCEDURE
| ObjectType::OBJECT_ROUTINE => {
let owa = node!(**object, Node::ObjectWithArgs);
FunctionWithArgTypes(owa).build(buffer)?;
}
ObjectType::OBJECT_OPERATOR => {
let owa = node!(**object, Node::ObjectWithArgs);
OperatorWithArgTypes(owa).build(buffer)?;
}
ObjectType::OBJECT_TABCONSTRAINT
| ObjectType::OBJECT_POLICY
| ObjectType::OBJECT_RULE
| ObjectType::OBJECT_TRIGGER => {
let list = node!(**object, Node::List);
if list.items.len() < 2 {
return Err(SqlError::Unsupported("list.items.len() < 2".into()));
}
let last = string_value!(list.items.iter().last().unwrap());
buffer.push_str("e_identifier(last));
buffer.push_str(" ON ");
AnyName(&list.items[0..list.items.len() - 1]).build(buffer)?;
}
ObjectType::OBJECT_DOMCONSTRAINT => {
let list = node!(**object, Node::List);
if list.items.len() < 2 {
return Err(SqlError::Unsupported("list.items.len() < 2".into()));
}
let last = string_value!(list.items.iter().last().unwrap());
buffer.push_str("e_identifier(last));
buffer.push_str(" ON DOMAIN ");
let typ = node!(list.items[0], Node::TypeName);
typ.build(buffer)?;
}
ObjectType::OBJECT_TRANSFORM => {
let list = node!(**object, Node::List);
if list.items.len() < 2 {
return Err(SqlError::Unsupported("list.items.len() < 2".into()));
}
buffer.push_str("FOR ");
node!(list.items[0], Node::TypeName).build(buffer)?;
buffer.push_str(" LANGUAGE ");
buffer.push_str("e_identifier(string_value!(list.items[1])));
}
ObjectType::OBJECT_OPCLASS | ObjectType::OBJECT_OPFAMILY => {
let list = node!(**object, Node::List);
if list.items.len() < 2 {
return Err(SqlError::Unsupported("list.items.len() < 2".into()));
}
AnyName(&list.items[1..]).build(buffer)?;
buffer.push_str(" USING ");
buffer.push_str("e_identifier(string_value!(list.items[0])));
}
ObjectType::OBJECT_LARGEOBJECT => {
SqlValue(object).build_with_context(buffer, Context::None)?;
}
ObjectType::OBJECT_CAST => {
let list = node!(**object, Node::List);
if list.items.len() < 2 {
return Err(SqlError::Unsupported("list.items.len() < 2".into()));
}
buffer.push('(');
node!(list.items[0], Node::TypeName).build(buffer)?;
buffer.push_str(" AS ");
node!(list.items[1], Node::TypeName).build(buffer)?;
buffer.push(')');
}
unexpected => unsupported!(unexpected),
}
buffer.push_str(" IS ");
if let Some(ref comment) = self.comment {
StringLiteral(comment).build(buffer)?;
} else {
buffer.push_str("NULL");
}
Ok(())
}
}
impl SqlBuilder for CommonTableExpr {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.ctename);
ColId(name).build(buffer)?;
if let Some(ref alias_column_names) = self.aliascolnames {
if !alias_column_names.is_empty() {
buffer.push('(');
NameList(alias_column_names).build(buffer)?;
buffer.push(')');
}
}
buffer.push_str(" AS ");
match *self.ctematerialized {
CTEMaterialize::CTEMaterializeDefault => {}
CTEMaterialize::CTEMaterializeAlways => buffer.push_str("MATERIALIZED "),
CTEMaterialize::CTEMaterializeNever => buffer.push_str("NOT MATERIALIZED "),
}
buffer.push('(');
let query = must!(self.ctequery);
PreparableStmt(query).build(buffer)?;
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for CompositeTypeStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let type_var = must!(self.typevar);
buffer.push_str("CREATE TYPE ");
(**type_var).build_with_context(buffer, Context::CreateType)?;
buffer.push_str(" AS (");
if let Some(ref list) = self.coldeflist {
for (index, col) in iter_only!(list, Node::ColumnDef).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
col.build(buffer)?;
}
}
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for Constraint {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if let Some(ref name) = self.conname {
buffer.push_str("CONSTRAINT ");
buffer.push_str(name);
buffer.push(' ');
}
match *self.contype {
ConstrType::CONSTR_NULL => buffer.push_str("NULL"),
ConstrType::CONSTR_NOTNULL => buffer.push_str("NOT NULL"),
ConstrType::CONSTR_DEFAULT => {
buffer.push_str("DEFAULT");
if let Some(ref raw) = self.raw_expr {
buffer.push(' ');
Expr(raw).build(buffer)?;
}
}
ConstrType::CONSTR_IDENTITY => {
buffer.push_str("GENERATED ");
match self.generated_when {
constants::ATTRIBUTE_IDENTITY_ALWAYS => buffer.push_str("ALWAYS "),
constants::ATTRIBUTE_IDENTITY_BY_DEFAULT => buffer.push_str("BY DEFAULT "),
unexpected => {
return Err(SqlError::Unsupported(format!(
"Unexpected attribute identity: {}",
unexpected
)));
}
}
buffer.push_str("AS IDENTITY");
if let Some(ref options) = self.options {
buffer.push(' ');
ParenthesizedSeqOptList(options).build(buffer)?;
}
}
ConstrType::CONSTR_GENERATED => {
if self.generated_when != constants::ATTRIBUTE_IDENTITY_ALWAYS {
return Err(SqlError::Unsupported(format!(
"Unexpected attribute identity: {}",
self.generated_when
)));
}
buffer.push_str("GENERATED ALWAYS AS (");
if let Some(ref raw) = self.raw_expr {
Expr(raw).build(buffer)?;
}
buffer.push_str(") STORED");
}
ConstrType::CONSTR_CHECK => {
buffer.push_str("CHECK (");
if let Some(ref raw) = self.raw_expr {
Expr(raw).build(buffer)?;
}
buffer.push(')');
}
ConstrType::CONSTR_PRIMARY => buffer.push_str("PRIMARY KEY"),
ConstrType::CONSTR_UNIQUE => buffer.push_str("UNIQUE"),
ConstrType::CONSTR_EXCLUSION => {
buffer.push_str("EXCLUDE ");
if let Some(ref method) = self.access_method {
if method.ne(constants::DEFAULT_INDEX_TYPE) {
buffer.push_str("USING ");
buffer.push_str("e_identifier(method));
buffer.push(' ');
}
}
buffer.push('(');
if let Some(ref exclusions) = self.exclusions {
for (index, exclusion) in iter_only!(exclusions, Node::List).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
if exclusion.items.len() != 2 {
return Err(SqlError::Unsupported("exclusion.items.len() != 2".into()));
}
node!(exclusion.items[0], Node::IndexElem).build(buffer)?;
buffer.push_str(" WITH ");
let list = node!(exclusion.items[1], Node::List);
AnyOperator(&list.items).build(buffer)?;
}
}
buffer.push(')');
if let Some(ref where_clause) = self.where_clause {
buffer.push_str(" WHERE (");
Expr(where_clause).build(buffer)?;
buffer.push(')');
}
}
ConstrType::CONSTR_FOREIGN => {
if let Some(ref attrs) = self.fk_attrs {
if !attrs.is_empty() {
buffer.push_str("FOREIGN KEY");
}
}
}
ConstrType::CONSTR_ATTR_DEFERRABLE => buffer.push_str("DEFERRABLE"),
ConstrType::CONSTR_ATTR_NOT_DEFERRABLE => buffer.push_str("NOT DEFERRABLE"),
ConstrType::CONSTR_ATTR_DEFERRED => buffer.push_str("INITIALLY DEFERRED"),
ConstrType::CONSTR_ATTR_IMMEDIATE => buffer.push_str("INITIALLY IMMEDIATE"),
}
if let Some(ref keys) = self.keys {
if !keys.is_empty() {
buffer.push_str(" (");
ColumnList(keys).build(buffer)?;
buffer.push(')');
}
}
if let Some(ref attrs) = self.fk_attrs {
if !attrs.is_empty() {
buffer.push_str(" (");
ColumnList(attrs).build(buffer)?;
buffer.push(')');
}
}
if let Some(ref table) = self.pktable {
buffer.push_str(" REFERENCES ");
(**table).build_with_context(buffer, Context::None)?;
if let Some(ref attrs) = self.pk_attrs {
if !attrs.is_empty() {
buffer.push_str(" (");
ColumnList(attrs).build(buffer)?;
buffer.push(')');
}
}
}
match self.fk_matchtype {
constants::FKCONSTR_MATCH_SIMPLE => {} constants::FKCONSTR_MATCH_FULL => buffer.push_str(" MATCH FULL"),
constants::FKCONSTR_MATCH_PARTIAL => {
return Err(SqlError::Unsupported("Not implemented in Postgres".into()));
}
_ => {} }
match self.fk_upd_action {
constants::FKCONSTR_ACTION_NOACTION => {} constants::FKCONSTR_ACTION_RESTRICT => buffer.push_str(" ON UPDATE RESTRICT"),
constants::FKCONSTR_ACTION_CASCADE => buffer.push_str(" ON UPDATE CASCADE"),
constants::FKCONSTR_ACTION_SETNULL => buffer.push_str(" ON UPDATE SET NULL"),
constants::FKCONSTR_ACTION_SETDEFAULT => buffer.push_str(" ON UPDATE SET DEFAULT"),
_ => {} }
match self.fk_del_action {
constants::FKCONSTR_ACTION_NOACTION => {} constants::FKCONSTR_ACTION_RESTRICT => buffer.push_str(" ON DELETE RESTRICT"),
constants::FKCONSTR_ACTION_CASCADE => buffer.push_str(" ON DELETE CASCADE"),
constants::FKCONSTR_ACTION_SETNULL => buffer.push_str(" ON DELETE SET NULL"),
constants::FKCONSTR_ACTION_SETDEFAULT => buffer.push_str(" ON DELETE SET DEFAULT"),
_ => {} }
if let Some(ref includes) = self.including {
if !includes.is_empty() {
buffer.push_str(" INCLUDE (");
ColumnList(includes).build(buffer)?;
buffer.push(')');
}
}
if let Some(ref name) = self.indexname {
buffer.push_str(" USING INDEX ");
buffer.push_str("e_identifier(name));
}
if let Some(ref space) = self.indexspace {
buffer.push_str(" USING INDEX TABLESPACE ");
buffer.push_str("e_identifier(space));
}
if self.deferrable {
buffer.push_str(" DEFERRABLE");
}
if self.initdeferred {
buffer.push_str(" INITIALLY DEFERRED");
}
if self.is_no_inherit {
buffer.push_str(" NO INHERIT");
}
if self.skip_validation {
buffer.push_str(" NOT VALID");
}
Ok(())
}
}
impl SqlBuilder for CopyStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
fn default_option_impl(
inner_buffer: &mut String,
element: &DefElem,
other: &str,
) -> Result<(), SqlError> {
inner_buffer.push_str(other);
if let Some(ref arg) = element.arg {
inner_buffer.push(' ');
match &**arg {
Node::String { sval: Some(value) } => {
BooleanOrString(value).build(inner_buffer)?
}
Node::Integer { .. } | Node::Float { .. } => {
NumericOnly(arg).build(inner_buffer)?
}
Node::A_Star(a_star) => a_star.build(inner_buffer)?,
Node::List(list) => {
inner_buffer.push('(');
for (sub, item) in list.items.iter().enumerate() {
if sub > 0 {
inner_buffer.push_str(", ");
}
BooleanOrString(string_value!(item)).build(inner_buffer)?;
}
inner_buffer.push(')');
}
unexpected => return Err(SqlError::UnexpectedNodeType(unexpected.name())),
}
}
Ok(())
}
buffer.push_str("COPY");
if let Some(ref relation) = self.relation {
buffer.push(' ');
(**relation).build_with_context(buffer, Context::None)?;
if let Some(ref attlist) = self.attlist {
if !attlist.is_empty() {
buffer.push('(');
ColumnList(attlist).build(buffer)?;
buffer.push(')');
}
}
}
if let Some(ref query) = self.query {
buffer.push_str(" (");
PreparableStmt(query).build(buffer)?;
buffer.push(')');
}
if self.is_from {
buffer.push_str(" FROM");
} else {
buffer.push_str(" TO");
}
if self.is_program {
buffer.push_str(" PROGRAM");
}
if let Some(ref filename) = self.filename {
buffer.push(' ');
StringLiteral(filename).build(buffer)?;
} else if self.is_from {
buffer.push_str(" STDIN");
} else {
buffer.push_str(" STDOUT");
}
if let Some(ref options) = self.options {
if !options.is_empty() {
buffer.push_str(" WITH (");
for (index, element) in iter_only!(options, Node::DefElem).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
let name = must!(element.defname);
match &name[..] {
"format" => {
buffer.push_str("FORMAT ");
let format = must!(element.arg);
let format = string_value!(**format);
match &format[..] {
"binary" => buffer.push_str("BINARY"),
"csv" => buffer.push_str("CSV"),
unexpected => {
return Err(SqlError::Unsupported(format!(
"Format type: {}",
unexpected
)));
}
}
}
"freeze" | "header" => {
let mut use_default_impl = false;
let mut value = None;
if let Some(arg) = &element.arg {
let val = int_value!(**arg).unwrap_or_default();
if val == 1 {
value = Some(val);
} else {
use_default_impl = true;
}
}
if use_default_impl {
default_option_impl(buffer, element, name)?;
} else {
buffer.push_str(&name.to_uppercase());
if let Some(val) = value {
buffer.push_str(&format!(" {}", val));
}
}
}
"delimiter" => {
let arg = must!(element.arg);
buffer.push_str("DELIMITER ");
StringLiteral(string_value!(**arg)).build(buffer)?;
}
"null" => {
let arg = must!(element.arg);
buffer.push_str("NULL ");
StringLiteral(string_value!(**arg)).build(buffer)?;
}
"quote" => {
let arg = must!(element.arg);
buffer.push_str("QUOTE ");
StringLiteral(string_value!(**arg)).build(buffer)?;
}
"escape" => {
let arg = must!(element.arg);
buffer.push_str("ESCAPE ");
StringLiteral(string_value!(**arg)).build(buffer)?;
}
"encoding" => {
let arg = must!(element.arg);
buffer.push_str("ENCODING ");
StringLiteral(string_value!(**arg)).build(buffer)?;
}
"force_quote" => {
let arg = must!(element.arg);
buffer.push_str("FORCE_QUOTE ");
match &**arg {
Node::A_Star(a_star) => a_star.build(buffer)?,
Node::List(list) => {
buffer.push('(');
ColumnList(&list.items).build(buffer)?;
buffer.push(')');
}
unexpected => {
return Err(SqlError::UnexpectedNodeType(unexpected.name()));
}
}
}
"force_not_null" => {
let arg = must!(element.arg);
let list = node!(**arg, Node::List);
buffer.push_str("FORCE_NOT_NULL (");
ColumnList(&list.items).build(buffer)?;
buffer.push(')');
}
"force_null" => {
let arg = must!(element.arg);
let list = node!(**arg, Node::List);
buffer.push_str("FORCE_NULL (");
ColumnList(&list.items).build(buffer)?;
buffer.push(')');
}
other => default_option_impl(buffer, element, other)?,
}
}
buffer.push(')');
}
}
if let Some(ref where_clause) = self.where_clause {
WhereClause(where_clause).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for CreateCastStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let source_type = must!(self.sourcetype);
let target_type = must!(self.targettype);
buffer.push_str("CREATE CAST (");
(**source_type).build(buffer)?;
buffer.push_str(" AS ");
(**target_type).build(buffer)?;
buffer.push(')');
if let Some(ref func) = self.func {
buffer.push_str(" WITH FUNCTION ");
FunctionWithArgTypes(func).build(buffer)?;
} else if self.inout {
buffer.push_str(" WITH INOUT");
} else {
buffer.push_str(" WITHOUT FUNCTION");
}
match *self.context {
CoercionContext::COERCION_IMPLICIT => buffer.push_str(" AS IMPLICIT"),
CoercionContext::COERCION_ASSIGNMENT => buffer.push_str(" AS ASSIGNMENT"),
CoercionContext::COERCION_EXPLICIT => {}
CoercionContext::COERCION_PLPGSQL => {}
}
Ok(())
}
}
impl SqlBuilder for CreateDomainStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let type_name = must!(self.type_name);
buffer.push_str("CREATE DOMAIN");
if let Some(ref domain_name) = self.domainname {
buffer.push(' ');
AnyName(domain_name).build(buffer)?;
}
buffer.push_str(" AS ");
(**type_name).build(buffer)?;
if let Some(ref coll) = self.coll_clause {
buffer.push(' ');
(**coll).build(buffer)?;
}
if let Some(ref constraints) = self.constraints {
for constraint in iter_only!(constraints, Node::Constraint) {
buffer.push(' ');
constraint.build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for CreateEnumStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let type_name = must!(self.type_name);
buffer.push_str("CREATE TYPE ");
AnyName(type_name).build(buffer)?;
buffer.push_str(" AS ENUM (");
if let Some(ref values) = self.vals {
for (index, value) in values.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
StringLiteral(string_value!(value)).build(buffer)?;
}
}
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for CreateExtensionStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let extname = must!(self.extname);
buffer.push_str("CREATE EXTENSION ");
if self.if_not_exists {
buffer.push_str("IF NOT EXISTS ");
}
ColId(extname).build(buffer)?;
if let Some(ref options) = self.options {
for elem in iter_only!(options, Node::DefElem) {
let name = must!(elem.defname);
match &name[..] {
"schema" => {
let arg = must!(elem.arg);
buffer.push_str(" SCHEMA ");
ColId(string_value!(**arg)).build(buffer)?;
}
"new_version" => {
let arg = must!(elem.arg);
buffer.push_str(" VERSION ");
NonReservedWordOrSconst(arg).build(buffer)?;
}
"cascade" => buffer.push_str(" CASCADE"),
unexpected => {
return Err(SqlError::Unsupported(format!(
"Extension option: {}",
unexpected
)));
}
}
}
}
Ok(())
}
}
impl SqlBuilder for CreateFunctionStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.funcname);
buffer.push_str("CREATE ");
if self.replace {
buffer.push_str("OR REPLACE ");
}
if self.is_procedure {
buffer.push_str("PROCEDURE ");
} else {
buffer.push_str("FUNCTION ");
}
FuncName(name).build(buffer)?;
let mut tables = Vec::new();
buffer.push('(');
if let Some(ref parameters) = self.parameters {
let mut comma = false;
for parameter in iter_only!(parameters, Node::FunctionParameter) {
if *parameter.mode != FunctionParameterMode::FUNC_PARAM_TABLE {
if comma {
buffer.push_str(", ");
} else {
comma = true;
}
parameter.build(buffer)?;
} else {
tables.push(parameter);
}
}
}
buffer.push(')');
if !tables.is_empty() {
buffer.push_str(" RETURNS TABLE (");
for (index, table) in tables.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
table.build(buffer)?;
}
buffer.push(')');
} else if let Some(ref return_type) = self.return_type {
buffer.push_str(" RETURNS ");
(**return_type).build(buffer)?;
}
if let Some(ref options) = self.options {
for option in iter_only!(options, Node::DefElem) {
buffer.push(' ');
let name = must!(option.defname);
if name.eq_ignore_ascii_case("AS") {
buffer.push_str("AS ");
let arg = must!(option.arg);
let list = node!(**arg, Node::List);
let list = node_vec_to_string_vec(&list.items);
for (index, item) in list.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
if !item.contains("$$") {
buffer.push_str("$$");
buffer.push_str(item);
buffer.push_str("$$");
} else {
StringLiteral(item).build(buffer)?;
}
}
} else if name.eq_ignore_ascii_case("LANGUAGE") {
let arg = must!(option.arg);
buffer.push_str("LANGUAGE ");
NonReservedWordOrSconst(arg).build(buffer)?;
} else if name.eq_ignore_ascii_case("transform") {
let arg = must!(option.arg);
let list = node!(**arg, Node::List);
buffer.push_str("TRANSFORM ");
for (index, item) in list.items.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
buffer.push_str("FOR TYPE ");
node!(item, Node::TypeName).build(buffer)?;
}
} else if name.eq_ignore_ascii_case("WINDOW") {
buffer.push_str("WINDOW");
} else {
CommonFuncOptItem(option).build(buffer)?;
}
}
}
Ok(())
}
}
impl SqlBuilder for CreateRangeStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let type_name = must!(self.type_name);
let definition = must!(self.params);
buffer.push_str("CREATE TYPE ");
AnyName(type_name).build(buffer)?;
buffer.push_str(" AS RANGE ");
Definition(definition).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for CreateSchemaStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("CREATE SCHEMA");
if self.if_not_exists {
buffer.push_str(" IF NOT EXISTS");
}
if let Some(ref name) = self.schemaname {
buffer.push(' ');
ColId(name).build(buffer)?;
}
if let Some(ref role) = self.authrole {
buffer.push_str(" AUTHORIZATION ");
(**role).build(buffer)?;
}
if let Some(ref elements) = self.schema_elts {
for el in elements.iter() {
buffer.push(' ');
SchemaStmt(el).build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for CreateSeqStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let sequence = must!(self.sequence);
buffer.push_str("CREATE ");
if let Some(temp) = persistence_from_code(sequence.relpersistence) {
buffer.push(' ');
buffer.push_str(temp);
}
buffer.push_str(" SEQUENCE");
if self.if_not_exists {
buffer.push_str(" IF NOT EXISTS");
}
(**sequence).build_with_context(buffer, Context::None)?;
if let Some(ref options) = self.options {
if !options.is_empty() {
buffer.push(' ');
SeqOptList(options).build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilderWithContext for CreateStmt {
fn build_with_context(&self, buffer: &mut String, context: Context) -> Result<(), SqlError> {
let relation = must!(self.relation);
buffer.push_str("CREATE ");
if context == Context::ForeignTable {
buffer.push_str("FOREIGN ");
}
if let Some(persistence) = persistence_from_code(relation.relpersistence) {
buffer.push_str(persistence);
buffer.push(' ');
}
buffer.push_str("TABLE ");
if self.if_not_exists {
buffer.push_str("IF NOT EXISTS ");
}
(**relation).build_with_context(buffer, Context::None)?;
if let Some(ref type_name) = self.of_typename {
buffer.push_str(" OF ");
(**type_name).build(buffer)?;
}
if self.partbound.is_some() {
if let Some(ref inh) = self.inh_relations {
if let Some(Node::RangeVar(range)) = inh.iter().next() {
buffer.push_str(" PARTITION OF ");
range.build_with_context(buffer, Context::None)?;
}
}
}
if let Some(ref table_elements) = self.table_elts {
if !table_elements.is_empty() {
buffer.push_str(" (");
for (index, item) in table_elements.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
item.build(buffer)?;
}
buffer.push(')')
} else if self.partbound.is_none() && self.of_typename.is_none() {
buffer.push_str(" ()");
}
} else if self.partbound.is_none() && self.of_typename.is_none() {
buffer.push_str(" ()");
}
if let Some(ref bound) = self.partbound {
buffer.push(' ');
(**bound).build(buffer)?;
} else if let Some(ref inh) = self.inh_relations {
if !inh.is_empty() {
buffer.push_str(" INHERITS (");
QualifiedNameList(inh).build(buffer)?;
buffer.push(')');
}
}
if let Some(ref spec) = self.partspec {
buffer.push(' ');
(**spec).build(buffer)?;
}
if let Some(ref access_method) = self.access_method {
buffer.push_str(" USING ");
buffer.push_str("e_identifier(access_method));
}
if let Some(ref options) = self.options {
OptWith(options).build(buffer)?;
}
match *self.oncommit {
OnCommitAction::ONCOMMIT_NOOP => {} OnCommitAction::ONCOMMIT_PRESERVE_ROWS => {
buffer.push_str(" ON COMMIT PRESERVE ROWS");
}
OnCommitAction::ONCOMMIT_DELETE_ROWS => {
buffer.push_str(" ON COMMIT DELETE ROWS");
}
OnCommitAction::ONCOMMIT_DROP => {
buffer.push_str(" ON COMMIT DROP");
}
}
if let Some(ref tablespace_name) = self.tablespacename {
buffer.push_str(" TABLESPACE ");
buffer.push_str("e_identifier(tablespace_name));
}
Ok(())
}
}
impl SqlBuilder for CreateTableAsStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let into = must!(self.into);
buffer.push_str("CREATE");
if let Some(ref rel) = into.rel {
if let Some(persistence) = persistence_from_code(rel.relpersistence) {
buffer.push(' ');
buffer.push_str(persistence);
}
}
match *self.objtype {
ObjectType::OBJECT_TABLE => buffer.push_str(" TABLE"),
ObjectType::OBJECT_MATVIEW => buffer.push_str(" MATERIALIZED VIEW"),
unsupported => return Err(SqlError::Unsupported(format!("{:?}", unsupported))),
}
if self.if_not_exists {
buffer.push_str(" IF NOT EXISTS");
}
buffer.push(' ');
(**into).build(buffer)?;
buffer.push_str(" AS ");
if let Some(ref query) = self.query {
match &**query {
Node::ExecuteStmt(stmt) => stmt.build(buffer)?,
Node::SelectStmt(stmt) => stmt.build(buffer)?,
unexpected => return Err(SqlError::UnexpectedNodeType(unexpected.name())),
}
}
if into.skip_data {
buffer.push_str(" WITH NO DATA");
}
Ok(())
}
}
impl SqlBuilder for CreateTableSpaceStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.tablespacename);
let location = must!(self.location);
buffer.push_str("CREATE TABLESPACE ");
ColId(name).build(buffer)?;
if let Some(ref owner) = self.owner {
buffer.push_str(" OWNER ");
(**owner).build(buffer)?;
}
buffer.push_str(" LOCATION ");
StringLiteral(location).build(buffer)?;
if let Some(ref options) = self.options {
buffer.push(' ');
OptWith(options).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for CreateTrigStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.trigname);
let func_name = must!(self.funcname);
let relation = must!(self.relation);
buffer.push_str("CREATE");
if self.isconstraint {
buffer.push_str(" CONSTRAINT");
}
buffer.push_str(" TRIGGER");
buffer.push_str(name);
buffer.push(' ');
match self.timing {
constants::trigger::TRIGGER_TYPE_BEFORE => buffer.push_str(" BEFORE"),
constants::trigger::TRIGGER_TYPE_AFTER => buffer.push_str(" AFTER"),
constants::trigger::TRIGGER_TYPE_INSTEAD => buffer.push_str(" INSTEAD"),
unknown => return Err(SqlError::Unsupported(format!("Timing: {}", unknown))),
}
let mut require_or = false;
if self.events & constants::trigger::TRIGGER_TYPE_INSERT > 0 {
buffer.push_str(" INSERT");
require_or = true;
}
if self.events & constants::trigger::TRIGGER_TYPE_DELETE > 0 {
if require_or {
buffer.push_str(" OR");
}
buffer.push_str(" DELETE");
require_or = true;
}
if self.events & constants::trigger::TRIGGER_TYPE_UPDATE > 0 {
if require_or {
buffer.push_str(" OR");
}
buffer.push_str(" UPDATE");
require_or = true;
if let Some(ref columns) = self.columns {
if !columns.is_empty() {
buffer.push_str(" OF");
ColumnList(columns).build(buffer)?;
}
}
}
if self.events & constants::trigger::TRIGGER_TYPE_TRUNCATE > 0 {
if require_or {
buffer.push_str(" OR");
}
buffer.push_str(" TRUNCATE");
}
buffer.push_str(" ON");
(**relation).build_with_context(buffer, Context::None)?;
if let Some(ref transitions) = self.transition_rels {
buffer.push_str(" REFERENCING");
for transition in iter_only!(transitions, Node::TriggerTransition) {
buffer.push(' ');
transition.build(buffer)?;
}
}
if let Some(ref constraint) = self.constrrel {
buffer.push_str(" FROM");
(**constraint).build_with_context(buffer, Context::None)?;
}
if self.deferrable {
buffer.push_str(" DEFERRABLE");
}
if self.initdeferred {
buffer.push_str(" INITIALLY DEFERRED");
}
if self.row {
buffer.push_str(" FOR EACH ROW");
}
if let Some(ref when_clause) = self.when_clause {
buffer.push_str(" WHEN (");
Expr(when_clause).build(buffer)?;
buffer.push(')');
}
buffer.push_str(" EXECUTE FUNCTION ");
FuncName(func_name).build(buffer)?;
buffer.push('(');
if let Some(ref args) = self.args {
for (index, arg) in node_vec_to_string_vec(args).iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
StringLiteral(arg).build(buffer)?;
}
}
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for CreatedbStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let dbname = must!(self.dbname);
buffer.push_str("CREATE DATABASE ");
ColId(dbname).build(buffer)?;
if let Some(ref options) = self.options {
if !options.is_empty() {
buffer.push(' ');
CreatedbOptList(options).build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for DefineStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("CREATE");
if self.replace {
buffer.push_str(" OR REPLACE")
}
match *self.kind {
ObjectType::OBJECT_AGGREGATE => buffer.push_str(" AGGREGATE"),
ObjectType::OBJECT_OPERATOR => buffer.push_str(" OPERATOR"),
ObjectType::OBJECT_TYPE => buffer.push_str(" TYPE"),
ObjectType::OBJECT_TSPARSER => buffer.push_str(" TEXT SEARCH PARSER"),
ObjectType::OBJECT_TSDICTIONARY => buffer.push_str(" TEXT SEARCH DICTIONARY"),
ObjectType::OBJECT_TSTEMPLATE => buffer.push_str(" TEXT SEARCH TEMPLATE"),
ObjectType::OBJECT_TSCONFIGURATION => buffer.push_str(" TEXT SEARCH CONFIGURATION"),
ObjectType::OBJECT_COLLATION => buffer.push_str(" COLLATION"),
unexpected => unsupported!(unexpected),
}
if self.if_not_exists {
buffer.push_str(" IF NOT EXISTS");
}
match *self.kind {
ObjectType::OBJECT_AGGREGATE => {
let name = must!(self.defnames);
buffer.push(' ');
FuncName(name).build(buffer)?;
}
ObjectType::OBJECT_OPERATOR => {
let name = must!(self.defnames);
buffer.push(' ');
AnyOperator(name).build(buffer)?;
}
ObjectType::OBJECT_TYPE
| ObjectType::OBJECT_TSPARSER
| ObjectType::OBJECT_TSTEMPLATE
| ObjectType::OBJECT_TSCONFIGURATION
| ObjectType::OBJECT_TSDICTIONARY
| ObjectType::OBJECT_COLLATION => {
let name = must!(self.defnames);
buffer.push(' ');
AnyName(name).build(buffer)?;
}
unexpected => unsupported!(unexpected),
}
if !self.oldstyle && *self.kind == ObjectType::OBJECT_AGGREGATE {
buffer.push(' ');
let args = must!(self.args);
AggrArgs(args).build(buffer)?;
}
if let Some(ref definition) = self.definition {
if *self.kind == ObjectType::OBJECT_COLLATION && definition.len() == 1 {
let elem = node!(definition[0], Node::DefElem);
let name = must!(elem.defname);
if name.eq("from") {
buffer.push_str(" FROM ");
let arg = must!(elem.arg);
let arg = node!(**arg, Node::List);
AnyName(&arg.items).build(buffer)?;
} else {
buffer.push(' ');
Definition(definition).build(buffer)?;
}
} else if !definition.is_empty() {
buffer.push(' ');
Definition(definition).build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for DeleteStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let relation = must!(self.relation);
if let Some(ref with) = self.with_clause {
(**with).build(buffer)?;
buffer.push(' ');
}
buffer.push_str("DELETE FROM ");
(**relation).build_with_context(buffer, Context::None)?;
if let Some(ref using) = self.using_clause {
buffer.push_str(" USING ");
FromList(using).build(buffer)?;
}
if let Some(ref clause) = self.where_clause {
buffer.push(' ');
WhereClause(clause).build(buffer)?;
}
if let Some(ref list) = self.returning_list {
if !list.is_empty() {
buffer.push_str(" RETURNING ");
TargetList(list).build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for DiscardStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("DISCARD ");
match *self.target {
DiscardMode::DISCARD_ALL => buffer.push_str("ALL"),
DiscardMode::DISCARD_PLANS => buffer.push_str("PLANS"),
DiscardMode::DISCARD_SEQUENCES => buffer.push_str("SEQUENCES"),
DiscardMode::DISCARD_TEMP => buffer.push_str("TEMP"),
}
Ok(())
}
}
impl SqlBuilder for DoStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("DO");
if let Some(ref args) = self.args {
for arg in iter_only!(args, Node::DefElem) {
if let Some(ref name) = arg.defname {
if name.eq("language") {
let arg = must!(arg.arg);
buffer.push_str(" LANGUAGE ");
buffer.push_str("e_identifier(string_value!(**arg)));
} else if name.eq("as") {
let arg = must!(arg.arg);
let arg = string_value!(**arg);
let delim = if arg.contains("$$") { "$outer$" } else { "$$" };
buffer.push(' ');
buffer.push_str(delim);
buffer.push_str(arg);
buffer.push_str(delim);
}
}
}
}
Ok(())
}
}
impl SqlBuilder for DropRoleStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let roles = must!(self.roles);
buffer.push_str("DROP ROLE ");
if self.missing_ok {
buffer.push_str("IF EXISTS ");
}
RoleList(roles).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for DropStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let objects = must!(self.objects);
buffer.push_str("DROP");
match *self.remove_type {
ObjectType::OBJECT_ACCESS_METHOD => buffer.push_str(" ACCESS METHOD"),
ObjectType::OBJECT_AGGREGATE => buffer.push_str(" AGGREGATE"),
ObjectType::OBJECT_CAST => buffer.push_str(" CAST"),
ObjectType::OBJECT_COLLATION => buffer.push_str(" COLLATION"),
ObjectType::OBJECT_CONVERSION => buffer.push_str(" CONVERSION"),
ObjectType::OBJECT_DOMAIN => buffer.push_str(" DOMAIN"),
ObjectType::OBJECT_EVENT_TRIGGER => buffer.push_str(" EVENT TRIGGER"),
ObjectType::OBJECT_EXTENSION => buffer.push_str(" EXTENSION"),
ObjectType::OBJECT_FDW => buffer.push_str(" FOREIGN DATA WRAPPER"),
ObjectType::OBJECT_FOREIGN_SERVER => buffer.push_str(" SERVER"),
ObjectType::OBJECT_FOREIGN_TABLE => buffer.push_str(" FOREIGN TABLE"),
ObjectType::OBJECT_FUNCTION => buffer.push_str(" FUNCTION"),
ObjectType::OBJECT_INDEX => buffer.push_str(" INDEX"),
ObjectType::OBJECT_LANGUAGE => buffer.push_str(" LANGUAGE"),
ObjectType::OBJECT_MATVIEW => buffer.push_str(" MATERIALIZED VIEW"),
ObjectType::OBJECT_OPCLASS => buffer.push_str(" OPERATOR CLASS"),
ObjectType::OBJECT_OPERATOR => buffer.push_str(" OPERATOR"),
ObjectType::OBJECT_OPFAMILY => buffer.push_str(" OPERATOR FAMILY"),
ObjectType::OBJECT_POLICY => buffer.push_str(" POLICY"),
ObjectType::OBJECT_PROCEDURE => buffer.push_str(" PROCEDURE"),
ObjectType::OBJECT_PUBLICATION => buffer.push_str(" PUBLICATION"),
ObjectType::OBJECT_ROUTINE => buffer.push_str(" ROUTINE"),
ObjectType::OBJECT_RULE => buffer.push_str(" RULE"),
ObjectType::OBJECT_SCHEMA => buffer.push_str(" SCHEMA"),
ObjectType::OBJECT_SEQUENCE => buffer.push_str(" SEQUENCE"),
ObjectType::OBJECT_STATISTIC_EXT => buffer.push_str(" STATISTICS"),
ObjectType::OBJECT_TABLE => buffer.push_str(" TABLE"),
ObjectType::OBJECT_TRANSFORM => buffer.push_str(" TRANSFORM"),
ObjectType::OBJECT_TRIGGER => buffer.push_str(" TRIGGER"),
ObjectType::OBJECT_TSCONFIGURATION => buffer.push_str(" TEXT SEARCH CONFIGURATION"),
ObjectType::OBJECT_TSDICTIONARY => buffer.push_str(" TEXT SEARCH DICTIONARY"),
ObjectType::OBJECT_TSPARSER => buffer.push_str(" TEXT SEARCH PARSER"),
ObjectType::OBJECT_TSTEMPLATE => buffer.push_str(" TEXT SEARCH TEMPLATE"),
ObjectType::OBJECT_TYPE => buffer.push_str(" TYPE"),
ObjectType::OBJECT_VIEW => buffer.push_str(" VIEW"),
unsupported => return Err(SqlError::Unsupported(format!("{:?}", unsupported))),
}
if self.concurrent {
buffer.push_str(" CONCURRENTLY");
}
if self.missing_ok {
buffer.push_str(" IF EXISTS");
}
match *self.remove_type {
ObjectType::OBJECT_TABLE
| ObjectType::OBJECT_SEQUENCE
| ObjectType::OBJECT_VIEW
| ObjectType::OBJECT_MATVIEW
| ObjectType::OBJECT_INDEX
| ObjectType::OBJECT_FOREIGN_TABLE
| ObjectType::OBJECT_COLLATION
| ObjectType::OBJECT_CONVERSION
| ObjectType::OBJECT_STATISTIC_EXT
| ObjectType::OBJECT_TSPARSER
| ObjectType::OBJECT_TSDICTIONARY
| ObjectType::OBJECT_TSTEMPLATE
| ObjectType::OBJECT_TSCONFIGURATION => {
buffer.push(' ');
AnyNameList(objects).build(buffer)?;
}
ObjectType::OBJECT_ACCESS_METHOD
| ObjectType::OBJECT_EVENT_TRIGGER
| ObjectType::OBJECT_EXTENSION
| ObjectType::OBJECT_FDW
| ObjectType::OBJECT_PUBLICATION
| ObjectType::OBJECT_SCHEMA
| ObjectType::OBJECT_FOREIGN_SERVER => {
buffer.push(' ');
NameList(objects).build(buffer)?;
}
ObjectType::OBJECT_POLICY | ObjectType::OBJECT_RULE | ObjectType::OBJECT_TRIGGER => {
let list = iter_only!(objects, Node::List)
.next()
.ok_or_else(|| SqlError::Missing("List node".into()))?;
if list.items.len() < 2 {
return Err(SqlError::Unsupported(format!(
"Unsupported format for policy/rule/trigger: {}",
list.items.len()
)));
}
buffer.push(' ');
let col_id = string_value!(list.items.iter().last().unwrap());
ColId(col_id).build(buffer)?;
buffer.push_str(" ON ");
let remainder = &list.items[0..list.items.len() - 1];
AnyName(remainder).build(buffer)?;
}
ObjectType::OBJECT_CAST => {
let list = iter_only!(objects, Node::List)
.next()
.ok_or_else(|| SqlError::Missing("List node".into()))?;
let types = iter_only!(list.items, Node::TypeName).collect::<Vec<_>>();
if types.len() != 2 {
return Err(SqlError::Unsupported(format!(
"Unsupported format for cast: {}",
list.items.len()
)));
}
buffer.push_str(" (");
types[0].build(buffer)?;
buffer.push_str(" AS ");
types[1].build(buffer)?;
buffer.push(')');
}
ObjectType::OBJECT_OPFAMILY | ObjectType::OBJECT_OPCLASS => {
let list = iter_only!(objects, Node::List)
.next()
.ok_or_else(|| SqlError::Missing("List node".into()))?;
if list.items.len() < 2 {
return Err(SqlError::Unsupported(format!(
"Unsupported format for op family/class: {}",
list.items.len()
)));
}
buffer.push(' ');
AnyName(&list.items[1..]).build(buffer)?;
buffer.push_str(" USING ");
ColId(string_value!(list.items[0])).build(buffer)?;
}
ObjectType::OBJECT_TRANSFORM => {
let list = iter_only!(objects, Node::List)
.next()
.ok_or_else(|| SqlError::Missing("List node".into()))?;
if list.items.len() < 2 {
return Err(SqlError::Unsupported(format!(
"Unsupported format for transform: {}",
list.items.len()
)));
}
buffer.push_str(" FOR ");
node!(list.items[0], Node::TypeName).build(buffer)?;
buffer.push_str(" LANGUAGE ");
ColId(string_value!(list.items[1])).build(buffer)?;
}
ObjectType::OBJECT_LANGUAGE => {
if objects.is_empty() {
return Err(SqlError::Unsupported(
"Empty objects for OBJECT_LANGUAGE".into(),
));
}
let value = string_value!(objects[0]);
buffer.push(' ');
StringLiteral(value).build(buffer)?;
}
ObjectType::OBJECT_TYPE | ObjectType::OBJECT_DOMAIN => {
buffer.push(' ');
for (index, obj) in iter_only!(objects, Node::TypeName).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
obj.build(buffer)?;
}
}
ObjectType::OBJECT_AGGREGATE => {
buffer.push(' ');
for (index, item) in iter_only!(objects, Node::ObjectWithArgs).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
AggregateWithArgTypes(item).build(buffer)?;
}
}
ObjectType::OBJECT_FUNCTION
| ObjectType::OBJECT_PROCEDURE
| ObjectType::OBJECT_ROUTINE => {
buffer.push(' ');
for (index, item) in iter_only!(objects, Node::ObjectWithArgs).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
FunctionWithArgTypes(item).build(buffer)?;
}
}
ObjectType::OBJECT_OPERATOR => {
buffer.push(' ');
for (index, item) in iter_only!(objects, Node::ObjectWithArgs).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
OperatorWithArgTypes(item).build(buffer)?;
}
}
unsupported => unsupported!(unsupported),
}
OptDropBehavior(&self.behavior).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for DropSubscriptionStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let sub_name = must!(self.subname);
buffer.push_str("DROP SUBSCRIPTION ");
if self.missing_ok {
buffer.push_str("IF EXISTS ");
}
buffer.push_str(sub_name);
Ok(())
}
}
impl SqlBuilder for DropTableSpaceStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let tablespace = must!(self.tablespacename);
buffer.push_str("DROP TABLESPACE ");
if self.missing_ok {
buffer.push_str("IF EXISTS ");
}
buffer.push_str(tablespace);
Ok(())
}
}
impl SqlBuilder for ExecuteStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.name);
buffer.push_str("EXECUTE ");
buffer.push_str("e_identifier(name));
if let Some(ref params) = self.params {
if !params.is_empty() {
buffer.push('(');
ExprList(params).build(buffer)?;
buffer.push(')');
}
}
Ok(())
}
}
impl SqlBuilder for ExplainStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("EXPLAIN");
if let Some(ref options) = self.options {
if !options.is_empty() {
buffer.push_str(" (");
for (index, element) in iter_only!(options, Node::DefElem).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
GenericDefElemName(must!(element.defname)).build(buffer)?;
if let Some(ref arg) = element.arg {
match &**arg {
Node::Integer { .. } | Node::Float { .. } => {
buffer.push(' ');
NumericOnly(arg).build(buffer)?;
}
Node::String { sval: Some(value) } => {
buffer.push(' ');
BooleanOrString(value).build(buffer)?;
}
unexpected => {
return Err(SqlError::UnexpectedNodeType(unexpected.name()));
}
}
}
}
buffer.push(')');
}
}
must!(self.query).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for FuncCall {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let func_name = must!(self.funcname);
let name = node_vec_to_string_vec(func_name);
if name.len() == 2 && name[0].eq("pg_catalog") && name[1].eq("overlay") {
let args = must!(self.args);
if args.len() == 4 {
buffer.push_str("OVERLAY(");
Expr(&args[0]).build(buffer)?;
buffer.push_str(" PLACING ");
Expr(&args[1]).build(buffer)?;
buffer.push_str(" FROM ");
Expr(&args[2]).build(buffer)?;
buffer.push_str(" FOR ");
Expr(&args[3]).build(buffer)?;
buffer.push(')');
return Ok(());
}
}
FuncName(func_name).build(buffer)?;
buffer.push('(');
if self.agg_distinct {
buffer.push_str("DISTINCT ");
}
if self.agg_star {
buffer.push('*');
} else if let Some(ref args) = self.args {
for (index, arg) in args.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
if self.func_variadic && index == args.len() - 1 {
buffer.push_str("VARIADIC ");
}
arg.build(buffer)?;
}
}
if let Some(ref agg_order) = self.agg_order {
if !self.agg_within_group {
buffer.push(' ');
SortClause(agg_order).build(buffer)?;
}
}
buffer.push(')');
if let Some(ref agg_order) = self.agg_order {
if self.agg_within_group {
buffer.push_str(" WITHIN GROUP (");
SortClause(agg_order).build(buffer)?;
buffer.push(')');
}
}
if let Some(ref filter) = self.agg_filter {
buffer.push_str(" FILTER (WHERE ");
Expr(filter).build(buffer)?;
buffer.push(')');
}
if let Some(ref over) = self.over {
buffer.push_str(" OVER ");
if let Some(ref name) = over.name {
buffer.push_str(name);
} else {
(**over).build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for FunctionParameter {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match *self.mode {
FunctionParameterMode::FUNC_PARAM_IN => buffer.push_str("IN"),
FunctionParameterMode::FUNC_PARAM_OUT => buffer.push_str("OUT"),
FunctionParameterMode::FUNC_PARAM_INOUT => buffer.push_str("INOUT"),
FunctionParameterMode::FUNC_PARAM_VARIADIC => buffer.push_str("VARIADIC"),
FunctionParameterMode::FUNC_PARAM_TABLE => {} FunctionParameterMode::FUNC_PARAM_DEFAULT => {}
}
if let Some(ref name) = self.name {
if !buffer.ends_with(' ') && !buffer.ends_with('(') {
buffer.push(' ');
}
buffer.push_str(name);
}
if let Some(ref arg_type) = self.arg_type {
if !buffer.ends_with(' ') && !buffer.ends_with('(') {
buffer.push(' ');
}
(**arg_type).build(buffer)?;
}
if let Some(ref def_expr) = self.defexpr {
buffer.push_str(" = ");
Expr(def_expr).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for GrantRoleStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let granted_roles = must!(self.granted_roles);
let grantee_roles = must!(self.grantee_roles);
if self.is_grant {
buffer.push_str("GRANT ");
} else {
buffer.push_str("REVOKE ");
}
for (index, grant) in iter_only!(granted_roles, Node::AccessPriv).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
grant.build(buffer)?;
}
if self.is_grant {
buffer.push_str(" TO ");
} else {
buffer.push_str(" FROM ");
}
RoleList(grantee_roles).build(buffer)?;
if let Some(ref opt) = self.opt {
for opt in iter_only!(opt, Node::DefElem) {
let opt_name = must!(opt.defname);
buffer.push_str(" WITH ");
buffer.push_str(opt_name.to_uppercase().as_str());
buffer.push(' ');
if let Some(ref arg) = opt.arg {
arg.build(buffer)?;
}
}
}
if let Some(ref grantor) = self.grantor {
buffer.push_str(" GRANTED BY ");
grantor.build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for GrantStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if self.is_grant {
buffer.push_str("GRANT");
} else {
buffer.push_str("REVOKE");
if self.grant_option {
buffer.push_str(" GRANT OPTION FOR");
}
}
if let Some(ref privileges) = self.privileges {
if privileges.is_empty() {
buffer.push_str(" ALL");
} else {
buffer.push(' ');
for (index, privilege) in iter_only!(privileges, Node::AccessPriv).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
privilege.build(buffer)?;
}
}
} else {
buffer.push_str(" ALL");
}
buffer.push_str(" ON ");
match *self.targtype {
GrantTargetType::ACL_TARGET_OBJECT => {
let objs = must!(self.objects);
match *self.objtype {
ObjectType::OBJECT_TABLE => {
QualifiedNameList(objs).build(buffer)?;
}
ObjectType::OBJECT_SEQUENCE => {
buffer.push_str("SEQUENCE ");
QualifiedNameList(objs).build(buffer)?;
}
ObjectType::OBJECT_FDW => {
buffer.push_str("FOREIGN DATA WRAPPER ");
NameList(objs).build(buffer)?;
}
ObjectType::OBJECT_FOREIGN_SERVER => {
buffer.push_str("FOREIGN SERVER ");
NameList(objs).build(buffer)?;
}
ObjectType::OBJECT_FUNCTION => {
buffer.push_str("FUNCTION ");
FunctionWithArgTypesList(objs).build(buffer)?;
}
ObjectType::OBJECT_PROCEDURE => {
buffer.push_str("PROCEDURE ");
FunctionWithArgTypesList(objs).build(buffer)?;
}
ObjectType::OBJECT_ROUTINE => {
buffer.push_str("ROUTINE ");
FunctionWithArgTypesList(objs).build(buffer)?;
}
ObjectType::OBJECT_DATABASE => {
buffer.push_str("DATABASE ");
NameList(objs).build(buffer)?;
}
ObjectType::OBJECT_DOMAIN => {
buffer.push_str("DOMAIN ");
AnyNameList(objs).build(buffer)?;
}
ObjectType::OBJECT_LANGUAGE => {
buffer.push_str("LANGUAGE ");
NameList(objs).build(buffer)?;
}
ObjectType::OBJECT_LARGEOBJECT => {
buffer.push_str("LARGE OBJECT ");
NumericOnlyList(objs).build(buffer)?;
}
ObjectType::OBJECT_SCHEMA => {
buffer.push_str("SCHEMA ");
NameList(objs).build(buffer)?;
}
ObjectType::OBJECT_TABLESPACE => {
buffer.push_str("TABLESPACE ");
NameList(objs).build(buffer)?;
}
ObjectType::OBJECT_TYPE => {
buffer.push_str("TYPE ");
AnyNameList(objs).build(buffer)?;
}
unexpected => unsupported!(unexpected),
}
}
GrantTargetType::ACL_TARGET_ALL_IN_SCHEMA => {
let objs = must!(self.objects);
match *self.objtype {
ObjectType::OBJECT_TABLE => {
buffer.push_str("ALL TABLES IN SCHEMA ");
NameList(objs).build(buffer)?;
}
ObjectType::OBJECT_SEQUENCE => {
buffer.push_str("ALL SEQUENCES IN SCHEMA ");
NameList(objs).build(buffer)?;
}
ObjectType::OBJECT_FUNCTION => {
buffer.push_str("ALL FUNCTIONS IN SCHEMA ");
NameList(objs).build(buffer)?;
}
ObjectType::OBJECT_PROCEDURE => {
buffer.push_str("ALL PROCEDURES IN SCHEMA ");
NameList(objs).build(buffer)?;
}
ObjectType::OBJECT_ROUTINE => {
buffer.push_str("ALL ROUTINES IN SCHEMA ");
NameList(objs).build(buffer)?;
}
unexpected => unsupported!(unexpected),
}
}
GrantTargetType::ACL_TARGET_DEFAULTS => match *self.objtype {
ObjectType::OBJECT_TABLE => buffer.push_str("TABLES"),
ObjectType::OBJECT_SEQUENCE => buffer.push_str("SEQUENCES"),
ObjectType::OBJECT_FUNCTION => buffer.push_str("FUNCTIONS"),
ObjectType::OBJECT_PROCEDURE => buffer.push_str("PROCEDURES"),
ObjectType::OBJECT_ROUTINE => buffer.push_str("ROUTINES"),
unexpected => unsupported!(unexpected),
},
}
if self.is_grant {
buffer.push_str(" TO ");
} else {
buffer.push_str(" FROM ");
}
let grantees = must!(self.grantees);
for (index, grantee) in iter_only!(grantees, Node::RoleSpec).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
grantee.build(buffer)?;
}
if self.is_grant && self.grant_option {
buffer.push_str(" WITH GRANT OPTION");
}
OptDropBehavior(&self.behavior).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for GroupingSet {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match *self.kind {
GroupingSetKind::GROUPING_SET_EMPTY => buffer.push_str("()"),
GroupingSetKind::GROUPING_SET_SIMPLE => unsupported!(self.kind),
GroupingSetKind::GROUPING_SET_ROLLUP => {
buffer.push_str("ROLLUP (");
if let Some(ref content) = self.content {
ExprList(content).build(buffer)?;
}
buffer.push(')');
}
GroupingSetKind::GROUPING_SET_CUBE => {
buffer.push_str("CUBE (");
if let Some(ref content) = self.content {
ExprList(content).build(buffer)?;
}
buffer.push(')');
}
GroupingSetKind::GROUPING_SET_SETS => {
buffer.push_str("GROUPING SETS (");
if let Some(ref content) = self.content {
GroupByList(content).build(buffer)?;
}
buffer.push(')');
}
}
Ok(())
}
}
impl SqlBuilder for IndexElem {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if let Some(ref name) = self.name {
ColId(name).build(buffer)?;
} else if let Some(ref expr) = self.expr {
match &**expr {
Node::FuncCall(func_call) => func_call.build(buffer)?,
Node::SQLValueFunction(sql_value_function) => sql_value_function.build(buffer)?,
Node::TypeCast(type_cast) => type_cast.build(buffer)?,
Node::CoalesceExpr(coalesce_expr) => coalesce_expr.build(buffer)?,
Node::MinMaxExpr(min_max_expr) => min_max_expr.build(buffer)?,
Node::XmlExpr(xml_expr) => xml_expr.build(buffer)?,
Node::XmlSerialize(xml_serialize) => xml_serialize.build(buffer)?,
other => {
buffer.push('(');
Expr(other).build(buffer)?;
buffer.push(')');
}
}
} else {
return Err(SqlError::Unsupported("Unsupported IndexElem".into()));
}
if let Some(ref collation) = self.collation {
buffer.push(' ');
Collate(collation).build(buffer)?;
}
if let Some(ref opclass) = self.opclass {
if !opclass.is_empty() {
buffer.push(' ');
AnyName(opclass).build(buffer)?;
if let Some(ref opclassopts) = self.opclassopts {
if !opclassopts.is_empty() {
RelOptions(opclassopts).build(buffer)?;
}
}
}
}
match *self.ordering {
SortByDir::SORTBY_DEFAULT => {}
SortByDir::SORTBY_ASC => buffer.push_str(" ASC"),
SortByDir::SORTBY_DESC => buffer.push_str(" DESC"),
SortByDir::SORTBY_USING => {}
}
match *self.nulls_ordering {
SortByNulls::SORTBY_NULLS_DEFAULT => {}
SortByNulls::SORTBY_NULLS_FIRST => buffer.push_str(" NULLS FIRST"),
SortByNulls::SORTBY_NULLS_LAST => buffer.push_str(" NULLS LAST"),
}
Ok(())
}
}
impl SqlBuilder for IndexStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let relation = must!(self.relation);
buffer.push_str("CREATE");
if self.unique {
buffer.push_str(" UNIQUE");
}
buffer.push_str(" INDEX");
if self.concurrent {
buffer.push_str(" CONCURRENTLY");
}
if self.if_not_exists {
buffer.push_str(" IF NOT EXISTS");
}
if let Some(ref name) = self.idxname {
buffer.push(' ');
buffer.push_str(name);
}
buffer.push_str(" ON ");
(**relation).build_with_context(buffer, Context::None)?;
if let Some(ref access_method) = self.access_method {
if access_method.ne(constants::DEFAULT_INDEX_TYPE) {
buffer.push_str(" USING ");
buffer.push_str("e_identifier(access_method));
}
}
buffer.push_str(" (");
if let Some(ref parameters) = self.index_params {
for (index, parameter) in iter_only!(parameters, Node::IndexElem).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
parameter.build(buffer)?;
}
}
buffer.push(')');
if let Some(ref parameters) = self.index_including_params {
if !parameters.is_empty() {
buffer.push_str(" INCLUDE (");
for (index, parameter) in iter_only!(parameters, Node::IndexElem).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
parameter.build(buffer)?;
}
buffer.push(')');
}
}
if let Some(ref options) = self.options {
buffer.push(' ');
OptWith(options).build(buffer)?;
}
if let Some(ref table_space) = self.table_space {
buffer.push_str(" TABLESPACE ");
buffer.push_str("e_identifier(table_space));
}
if let Some(ref where_clause) = self.where_clause {
buffer.push(' ');
WhereClause(where_clause).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for InferClause {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if let Some(ref elements) = self.index_elems {
if !elements.is_empty() {
buffer.push('(');
for (index, el) in iter_only!(elements, Node::IndexElem).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
el.build(buffer)?
}
buffer.push(')');
}
}
if let Some(ref name) = self.conname {
if !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("ON CONSTRAINT ");
buffer.push_str("e_identifier(name));
}
if let Some(ref clause) = self.where_clause {
if !buffer.ends_with(' ') {
buffer.push(' ');
}
WhereClause(clause).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for InsertStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if let Some(ref with) = self.with_clause {
(**with).build(buffer)?;
buffer.push(' ');
}
let relation = must!(self.relation);
buffer.push_str("INSERT INTO ");
(**relation).build_with_context(buffer, Context::InsertRelation)?;
if let Some(ref cols) = self.cols {
if !cols.is_empty() {
buffer.push_str(" (");
InsertColumnList(cols).build(buffer)?;
buffer.push(')');
}
}
match *self.override_ {
OverridingKind::OVERRIDING_NOT_SET => {} OverridingKind::OVERRIDING_USER_VALUE => buffer.push_str(" OVERRIDING USER VALUE"),
OverridingKind::OVERRIDING_SYSTEM_VALUE => buffer.push_str(" OVERRIDING SYSTEM VALUE"),
}
if let Some(ref stmt) = self.select_stmt {
buffer.push(' ');
(**stmt).build(buffer)?;
} else {
buffer.push_str(" DEFAULT VALUES");
}
if let Some(ref conflict) = self.on_conflict_clause {
buffer.push(' ');
(**conflict).build(buffer)?;
}
if let Some(ref returning) = self.returning_list {
if !returning.is_empty() {
buffer.push_str(" RETURNING ");
TargetList(returning).build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for LoadStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let filename = must!(self.filename);
buffer.push_str("LOAD ");
StringLiteral(filename).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for LockStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let relations = must!(self.relations);
buffer.push_str("LOCK TABLE ");
RelationExprList(relations).build(buffer)?;
if self.mode != constants::lock::AccessExclusiveLock {
buffer.push_str(" IN ");
match self.mode {
constants::lock::AccessShareLock => buffer.push_str("ACCESS SHARE"),
constants::lock::RowShareLock => buffer.push_str("ROW SHARE"),
constants::lock::RowExclusiveLock => buffer.push_str("ROW EXCLUSIVE"),
constants::lock::ShareUpdateExclusiveLock => {
buffer.push_str("SHARE UPDATE EXCLUSIVE")
}
constants::lock::ShareLock => buffer.push_str("SHARE"),
constants::lock::ShareRowExclusiveLock => buffer.push_str("SHARE ROW EXCLUSIVE"),
constants::lock::ExclusiveLock => buffer.push_str("EXCLUSIVE"),
constants::lock::AccessExclusiveLock => buffer.push_str("ACCESS EXCLUSIVE"),
unsupported => {
return Err(SqlError::Unsupported(format!(
"Unknown lock type: {}",
unsupported
)));
}
}
buffer.push_str(" MODE");
}
if self.nowait {
buffer.push_str(" NOWAIT");
}
Ok(())
}
}
impl SqlBuilder for LockingClause {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match *self.strength {
LockClauseStrength::LCS_NONE => {}
LockClauseStrength::LCS_FORKEYSHARE => buffer.push_str(" FOR KEY SHARE"),
LockClauseStrength::LCS_FORSHARE => buffer.push_str(" FOR SHARE"),
LockClauseStrength::LCS_FORNOKEYUPDATE => buffer.push_str(" FOR NO KEY UPDATE"),
LockClauseStrength::LCS_FORUPDATE => buffer.push_str(" FOR UPDATE"),
}
if let Some(ref rels) = self.locked_rels {
buffer.push_str(" OF ");
QualifiedNameList(rels).build(buffer)?;
}
match *self.wait_policy {
LockWaitPolicy::LockWaitBlock => {}
LockWaitPolicy::LockWaitSkip => buffer.push_str(" SKIP LOCKED"),
LockWaitPolicy::LockWaitError => buffer.push_str(" NOWAIT"),
}
Ok(())
}
}
impl SqlBuilder for OnConflictClause {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("ON CONFLICT");
if let Some(ref infer) = self.infer {
buffer.push(' ');
(**infer).build(buffer)?;
}
match *self.action {
OnConflictAction::ONCONFLICT_NONE => {}
OnConflictAction::ONCONFLICT_NOTHING => buffer.push_str(" DO NOTHING"),
OnConflictAction::ONCONFLICT_UPDATE => buffer.push_str(" DO UPDATE"),
}
if let Some(ref list) = self.target_list {
if !list.is_empty() {
buffer.push_str(" SET ");
SetClauseList(list).build(buffer)?;
}
}
if let Some(ref clause) = self.where_clause {
buffer.push(' ');
WhereClause(clause).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for ParamRef {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if self.number == 0 {
buffer.push('?');
} else {
buffer.push_str(&format!("${}", self.number));
}
Ok(())
}
}
impl SqlBuilder for PartitionBoundSpec {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if self.is_default {
buffer.push_str("DEFAULT");
return Ok(());
}
buffer.push_str("FOR VALUES ");
match self.strategy {
constants::PARTITION_STRATEGY_HASH => {
buffer.push_str(&format!(
"WITH (MODULUS {}, REMAINDER {})",
self.modulus, self.remainder
));
}
constants::PARTITION_STRATEGY_LIST => {
buffer.push_str("IN (");
if let Some(ref data) = self.listdatums {
ExprList(data).build(buffer)?;
}
buffer.push(')');
}
constants::PARTITION_STRATEGY_RANGE => {
buffer.push_str("FROM (");
if let Some(ref data) = self.lowerdatums {
ExprList(data).build(buffer)?;
}
buffer.push_str(") TO (");
if let Some(ref data) = self.upperdatums {
ExprList(data).build(buffer)?;
}
buffer.push(')');
}
unexpected => {
return Err(SqlError::Unsupported(format!(
"Partition Strategy: {}",
unexpected
)));
}
}
Ok(())
}
}
impl SqlBuilder for PartitionCmd {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.name);
(**name).build_with_context(buffer, Context::None)?;
if let Some(ref bound) = self.bound {
buffer.push(' ');
(**bound).build(buffer)?;
}
if self.concurrent {
buffer.push_str(" CONCURRENTLY");
}
Ok(())
}
}
impl SqlBuilder for PartitionElem {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if let Some(ref name) = self.name {
ColId(name).build(buffer)?;
} else if let Some(ref expr) = self.expr {
buffer.push('(');
Expr(expr).build(buffer)?;
buffer.push(')');
}
if let Some(ref collate) = self.collation {
buffer.push(' ');
Collate(collate).build(buffer)?;
}
if let Some(ref op) = self.opclass {
buffer.push(' ');
AnyName(op).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for PartitionStrategy {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match *self {
PartitionStrategy::PARTITION_STRATEGY_LIST => buffer.push_str("LIST"),
PartitionStrategy::PARTITION_STRATEGY_RANGE => buffer.push_str("RANGE"),
PartitionStrategy::PARTITION_STRATEGY_HASH => buffer.push_str("HASH"),
}
Ok(())
}
}
impl SqlBuilder for PartitionSpec {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("PARTITION BY ");
self.strategy.build(buffer)?;
buffer.push('(');
if let Some(ref params) = self.part_params {
for (index, elem) in iter_only!(params, Node::PartitionElem).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
elem.build(buffer)?;
}
}
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for PrepareStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let col_id = must!(self.name);
let query = must!(self.query);
buffer.push_str("PREPARE ");
ColId(col_id).build(buffer)?;
if let Some(ref argtypes) = self.argtypes {
if !argtypes.is_empty() {
buffer.push('(');
TypeList(argtypes).build(buffer)?;
buffer.push(')');
}
}
buffer.push_str(" AS ");
PreparableStmt(query).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for RangeFunction {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if self.lateral {
if !buffer.is_empty() && !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("LATERAL ");
}
if self.is_rowsfrom {
let functions = must!(self.functions);
if !buffer.is_empty() && !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("ROWS FROM (");
for (index, list) in functions.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
let list = node!(list, Node::List);
if list.items.len() != 2 {
return Err(SqlError::Unsupported("list.items.len() != 2".into()));
}
FuncExprWindowless(&list.items[0]).build(buffer)?;
buffer.push(' ');
let column_def_list = node!(list.items[1], Node::List);
if !column_def_list.items.is_empty() {
buffer.push_str("AS (");
for (index, col) in
iter_only!(column_def_list.items, Node::ColumnDef).enumerate()
{
if index > 0 {
buffer.push_str(", ");
}
col.build(buffer)?;
}
buffer.push(')');
}
}
buffer.push(')');
} else if let Some(ref func) = self.functions {
if let Some(Node::List(list)) = func.first() {
if let Some(func) = list.items.first() {
func.build(buffer)?;
}
}
}
if self.ordinality {
if !buffer.is_empty() && !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("WITH ORDINALITY ");
}
if let Some(ref alias) = self.alias {
buffer.push(' ');
(**alias).build(buffer)?;
}
if let Some(ref columns) = self.coldeflist {
if self.alias.is_none() {
buffer.push_str(" AS ");
} else {
buffer.push(' ');
}
buffer.push('(');
let mut iter = columns.iter().peekable();
while let Some(col) = iter.next() {
col.build(buffer)?;
if iter.peek().is_some() {
buffer.push_str(", ");
}
}
buffer.push(')');
}
Ok(())
}
}
impl SqlBuilder for RangeSubselect {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let select = must!(self.subquery);
if self.lateral {
buffer.push_str("LATERAL ");
}
buffer.push('(');
node!(**select, Node::SelectStmt).build(buffer)?;
buffer.push(')');
if let Some(ref alias) = self.alias {
buffer.push(' ');
(**alias).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for RangeTableFunc {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if self.lateral {
buffer.push_str("LATERAL ");
}
buffer.push_str("xmltable(");
if let Some(ref namespaces) = self.namespaces {
buffer.push_str("xmlnamespaces(");
XmlNamespaceList(namespaces).build(buffer)?;
buffer.push_str("), ");
}
buffer.push('(');
let expr = must!(self.rowexpr);
Expr(expr).build(buffer)?;
buffer.push(')');
buffer.push_str(" PASSING ");
let expr = must!(self.docexpr);
Expr(expr).build(buffer)?;
buffer.push_str(" COLUMNS ");
let columns = must!(self.columns);
for (index, col) in iter_only!(columns, Node::RangeTableFuncCol).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
col.build(buffer)?;
}
buffer.push(')');
if let Some(ref alias) = self.alias {
buffer.push_str(" AS ");
(**alias).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for RangeTableFuncCol {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let colname = must!(self.colname);
buffer.push_str("e_identifier(colname));
if self.for_ordinality {
buffer.push_str(" FOR ORDINALITY");
} else {
let type_name = must!(self.type_name);
buffer.push(' ');
(**type_name).build(buffer)?;
if let Some(ref expr) = self.colexpr {
buffer.push_str(" PATH ");
Expr(expr).build(buffer)?;
}
if let Some(ref expr) = self.coldefexpr {
buffer.push_str(" DEFAULT ");
Expr(expr).build(buffer)?;
}
if self.is_not_null {
buffer.push_str(" NOT NULL");
}
}
Ok(())
}
}
impl SqlBuilder for RangeTableSample {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let relation = must!(self.relation);
let relation = node!(**relation, Node::RangeVar);
let method = must!(self.method);
relation.build_with_context(buffer, Context::None)?;
buffer.push_str(" TABLESAMPLE ");
FuncName(method).build(buffer)?;
buffer.push('(');
if let Some(ref args) = self.args {
ExprList(args).build(buffer)?;
}
buffer.push(')');
if let Some(ref repeatable) = self.repeatable {
buffer.push_str(" REPEATABLE (");
Expr(repeatable).build(buffer)?;
buffer.push(')');
}
Ok(())
}
}
impl SqlBuilder for RenameStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("ALTER");
match *self.rename_type {
ObjectType::OBJECT_AGGREGATE => buffer.push_str(" AGGREGATE"),
ObjectType::OBJECT_COLLATION => buffer.push_str(" COLLATION"),
ObjectType::OBJECT_CONVERSION => buffer.push_str(" CONVERSION"),
ObjectType::OBJECT_DATABASE => buffer.push_str(" DATABASE"),
ObjectType::OBJECT_DOMAIN | ObjectType::OBJECT_DOMCONSTRAINT => {
buffer.push_str(" DOMAIN")
}
ObjectType::OBJECT_FDW => buffer.push_str(" FOREIGN DATA WRAPPER"),
ObjectType::OBJECT_FUNCTION => buffer.push_str(" FUNCTION"),
ObjectType::OBJECT_ROLE => buffer.push_str(" ROLE"),
ObjectType::OBJECT_LANGUAGE => buffer.push_str(" LANGUAGE"),
ObjectType::OBJECT_OPCLASS => buffer.push_str(" OPERATOR CLASS"),
ObjectType::OBJECT_OPFAMILY => buffer.push_str(" OPERATOR FAMILY"),
ObjectType::OBJECT_POLICY => buffer.push_str(" POLICY"),
ObjectType::OBJECT_PROCEDURE => buffer.push_str(" PROCEDURE"),
ObjectType::OBJECT_PUBLICATION => buffer.push_str(" PUBLICATION"),
ObjectType::OBJECT_ROUTINE => buffer.push_str(" ROUTINE"),
ObjectType::OBJECT_SCHEMA => buffer.push_str(" SCHEMA"),
ObjectType::OBJECT_FOREIGN_SERVER => buffer.push_str(" SERVER"),
ObjectType::OBJECT_SUBSCRIPTION => buffer.push_str(" SUBSCRIPTION"),
ObjectType::OBJECT_TABLE | ObjectType::OBJECT_TABCONSTRAINT => {
buffer.push_str(" TABLE")
}
ObjectType::OBJECT_COLUMN => match *self.relation_type {
ObjectType::OBJECT_TABLE => buffer.push_str(" TABLE"),
ObjectType::OBJECT_FOREIGN_TABLE => buffer.push_str(" FOREIGN TABLE"),
ObjectType::OBJECT_VIEW => buffer.push_str(" VIEW"),
ObjectType::OBJECT_MATVIEW => buffer.push_str(" MATERIALIZED VIEW"),
ty => unsupported!(ty),
},
ObjectType::OBJECT_SEQUENCE => buffer.push_str(" SEQUENCE"),
ObjectType::OBJECT_VIEW => buffer.push_str(" VIEW"),
ObjectType::OBJECT_MATVIEW => buffer.push_str(" MATERIALIZED VIEW"),
ObjectType::OBJECT_INDEX => buffer.push_str(" INDEX"),
ObjectType::OBJECT_FOREIGN_TABLE => buffer.push_str(" FOREIGN TABLE"),
ObjectType::OBJECT_RULE => buffer.push_str(" RULE"),
ObjectType::OBJECT_TRIGGER => buffer.push_str(" TRIGGER"),
ObjectType::OBJECT_EVENT_TRIGGER => buffer.push_str(" EVENT TRIGGER"),
ObjectType::OBJECT_TABLESPACE => buffer.push_str(" TABLESPACE"),
ObjectType::OBJECT_STATISTIC_EXT => buffer.push_str(" STATISTICS"),
ObjectType::OBJECT_TSPARSER => buffer.push_str(" TEXT SEARCH PARSER"),
ObjectType::OBJECT_TSDICTIONARY => buffer.push_str(" TEXT SEARCH DICTIONARY"),
ObjectType::OBJECT_TSTEMPLATE => buffer.push_str(" TEXT SEARCH TEMPLATE"),
ObjectType::OBJECT_TSCONFIGURATION => buffer.push_str(" TEXT SEARCH CONFIGURATION"),
ObjectType::OBJECT_TYPE | ObjectType::OBJECT_ATTRIBUTE => buffer.push_str(" TYPE"),
ty => unsupported!(ty),
}
if self.missing_ok {
buffer.push_str(" IF EXISTS");
}
match *self.rename_type {
ObjectType::OBJECT_AGGREGATE => {
let object = must!(self.object);
let object = node!(**object, Node::ObjectWithArgs);
buffer.push(' ');
AggregateWithArgTypes(object).build(buffer)?;
buffer.push_str(" RENAME");
}
ObjectType::OBJECT_DOMCONSTRAINT => {
let object = must!(self.object);
let list = node!(**object, Node::List);
buffer.push(' ');
AnyName(&list.items).build(buffer)?;
buffer.push_str(" RENAME CONSTRAINT ");
buffer.push_str("e_identifier(must!(self.subname)));
}
ObjectType::OBJECT_OPCLASS | ObjectType::OBJECT_OPFAMILY => {
let object = must!(self.object);
let list = node!(**object, Node::List);
buffer.push(' ');
AnyName(&list.items[1..]).build(buffer)?;
buffer.push_str(" USING ");
buffer.push_str("e_identifier(string_value!(list.items[0])));
buffer.push_str(" RENAME");
}
ObjectType::OBJECT_POLICY => {
buffer.push(' ');
buffer.push_str("e_identifier(must!(self.subname)));
buffer.push_str(" ON ");
must!(self.relation).build_with_context(buffer, Context::None)?;
buffer.push_str(" RENAME");
}
ObjectType::OBJECT_FUNCTION
| ObjectType::OBJECT_PROCEDURE
| ObjectType::OBJECT_ROUTINE => {
let object = must!(self.object);
let object = node!(**object, Node::ObjectWithArgs);
buffer.push(' ');
FunctionWithArgTypes(object).build(buffer)?;
buffer.push_str(" RENAME");
}
ObjectType::OBJECT_SUBSCRIPTION => {
let object = must!(self.object);
let col_id = string_value!(**object);
buffer.push(' ');
ColId(col_id).build(buffer)?;
buffer.push_str(" RENAME");
}
ObjectType::OBJECT_TABLE
| ObjectType::OBJECT_SEQUENCE
| ObjectType::OBJECT_VIEW
| ObjectType::OBJECT_MATVIEW
| ObjectType::OBJECT_INDEX
| ObjectType::OBJECT_FOREIGN_TABLE => {
buffer.push(' ');
must!(self.relation).build_with_context(buffer, Context::None)?;
buffer.push_str(" RENAME");
}
ObjectType::OBJECT_COLUMN => {
buffer.push(' ');
must!(self.relation).build_with_context(buffer, Context::None)?;
buffer.push_str(" RENAME COLUMN ");
buffer.push_str("e_identifier(must!(self.subname)));
}
ObjectType::OBJECT_TABCONSTRAINT => {
buffer.push(' ');
must!(self.relation).build_with_context(buffer, Context::None)?;
buffer.push_str(" RENAME CONSTRAINT ");
buffer.push_str("e_identifier(must!(self.subname)));
}
ObjectType::OBJECT_RULE | ObjectType::OBJECT_TRIGGER => {
buffer.push(' ');
buffer.push_str("e_identifier(must!(self.subname)));
buffer.push_str(" ON ");
must!(self.relation).build_with_context(buffer, Context::None)?;
buffer.push_str(" RENAME");
}
ObjectType::OBJECT_FDW
| ObjectType::OBJECT_LANGUAGE
| ObjectType::OBJECT_PUBLICATION
| ObjectType::OBJECT_FOREIGN_SERVER
| ObjectType::OBJECT_EVENT_TRIGGER => {
buffer.push(' ');
let object = must!(self.object);
buffer.push_str("e_identifier(string_value!(**object)));
buffer.push_str(" RENAME");
}
ObjectType::OBJECT_DATABASE
| ObjectType::OBJECT_ROLE
| ObjectType::OBJECT_SCHEMA
| ObjectType::OBJECT_TABLESPACE => {
buffer.push(' ');
buffer.push_str("e_identifier(must!(self.subname)));
buffer.push_str(" RENAME");
}
ObjectType::OBJECT_COLLATION
| ObjectType::OBJECT_CONVERSION
| ObjectType::OBJECT_DOMAIN
| ObjectType::OBJECT_STATISTIC_EXT
| ObjectType::OBJECT_TSPARSER
| ObjectType::OBJECT_TSDICTIONARY
| ObjectType::OBJECT_TSTEMPLATE
| ObjectType::OBJECT_TSCONFIGURATION
| ObjectType::OBJECT_TYPE => {
let object = must!(self.object);
let list = node!(**object, Node::List);
buffer.push(' ');
AnyName(&list.items).build(buffer)?;
buffer.push_str(" RENAME");
}
ObjectType::OBJECT_ATTRIBUTE => {
buffer.push(' ');
must!(self.relation).build_with_context(buffer, Context::AlterType)?;
buffer.push_str(" RENAME ATTRIBUTE ");
buffer.push_str("e_identifier(must!(self.subname)));
}
other => unsupported!(other),
}
buffer.push_str(" TO ");
buffer.push_str("e_identifier(must!(self.newname)));
OptDropBehavior(&self.behavior).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for ReplicaIdentityStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match self.identity_type {
constants::REPLICA_IDENTITY_NOTHING => buffer.push_str("NOTHING"),
constants::REPLICA_IDENTITY_FULL => buffer.push_str("FULL"),
constants::REPLICA_IDENTITY_DEFAULT => buffer.push_str("DEFAULT"),
constants::REPLICA_IDENTITY_INDEX => {
let name = must!(self.name);
buffer.push_str("USING INDEX ");
buffer.push_str("e_identifier(name));
}
_ => {}
}
Ok(())
}
}
impl SqlBuilder for ResTarget {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let val = must!(self.val);
(**val).build(buffer)?;
if let Some(ref name) = self.name {
buffer.push_str(&format!(" AS {}", quote_identifier(name)));
}
Ok(())
}
}
impl SqlBuilder for RoleSpec {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match *self.roletype {
RoleSpecType::ROLESPEC_CSTRING => {
buffer.push_str("e_identifier(must!(self.rolename)));
}
RoleSpecType::ROLESPEC_CURRENT_USER => buffer.push_str("CURRENT_USER"),
RoleSpecType::ROLESPEC_SESSION_USER => buffer.push_str("SESSION_USER"),
RoleSpecType::ROLESPEC_PUBLIC => buffer.push_str("public"),
RoleSpecType::ROLESPEC_CURRENT_ROLE => buffer.push_str("CURRENT_ROLE"),
}
Ok(())
}
}
impl SqlBuilder for SelectStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if let Some(ref with) = self.with_clause {
(**with).build(buffer)?;
}
match *self.op {
SetOperation::SETOP_NONE if self.values_lists.is_some() => {
let values = must!(self.values_lists);
buffer.push_str("VALUES ");
for (index, value) in values.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
buffer.push('(');
let list = node!(value, Node::List);
ExprList(&list.items).build(buffer)?;
buffer.push(')');
}
}
SetOperation::SETOP_NONE if self.values_lists.is_none() => {
if !buffer.is_empty() && !buffer.ends_with('(') && !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("SELECT ");
if let Some(ref target_list) = self.target_list {
if let Some(ref distinct) = self.distinct_clause {
buffer.push_str("DISTINCT ");
if !distinct.is_empty() {
buffer.push_str("ON (");
ExprList(distinct).build(buffer)?;
buffer.push_str(") ");
}
}
for (index, target) in target_list.iter().enumerate() {
let target = node!(target, Node::ResTarget);
if index > 0 {
buffer.push_str(", ");
}
target.build(buffer)?;
}
}
if let Some(ref into) = self.into_clause {
if !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("INTO ");
if let Some(ref rel) = into.rel {
if let Some(persistence) = persistence_from_code(rel.relpersistence) {
buffer.push_str(&format!("{} ", persistence));
}
}
(**into).build(buffer)?;
}
if let Some(ref from_clause) = self.from_clause {
if !buffer.ends_with(' ') {
buffer.push(' ');
}
FromClause(from_clause).build(buffer)?;
}
if let Some(ref where_clause) = self.where_clause {
buffer.push(' ');
WhereClause(where_clause).build(buffer)?;
}
if let Some(ref group) = self.group_clause {
buffer.push_str(" GROUP BY ");
GroupByList(group).build(buffer)?;
}
if let Some(ref having) = self.having_clause {
buffer.push_str(" HAVING ");
Expr(having).build(buffer)?;
}
if let Some(ref window) = self.window_clause {
buffer.push_str(" WINDOW ");
for (index, node) in window.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
let def = node!(node, Node::WindowDef);
let name = must!(def.name);
buffer.push_str(name);
buffer.push_str(" AS ");
def.build(buffer)?;
}
}
}
SetOperation::SETOP_UNION
| SetOperation::SETOP_INTERSECT
| SetOperation::SETOP_EXCEPT => {
if !buffer.is_empty() && !buffer.ends_with('(') && !buffer.ends_with(' ') {
buffer.push(' ');
}
let left = must!(self.larg);
let right = must!(self.rarg);
fn need_parenthesis(stmt: &SelectStmt) -> bool {
if let Some(ref sort) = stmt.sort_clause {
if !sort.is_empty() {
return true;
}
}
if stmt.limit_offset.is_some()
|| stmt.limit_count.is_some()
|| stmt.with_clause.is_some()
{
return true;
}
if let Some(ref lock) = stmt.locking_clause {
if !lock.is_empty() {
return true;
}
}
(*stmt.op).ne(&SetOperation::SETOP_NONE)
}
let left_parenthesis = need_parenthesis(left);
if left_parenthesis {
buffer.push('(');
}
(**left).build(buffer)?;
if left_parenthesis {
buffer.push(')');
}
match *self.op {
SetOperation::SETOP_NONE => {}
SetOperation::SETOP_UNION => buffer.push_str(" UNION "),
SetOperation::SETOP_INTERSECT => buffer.push_str(" INTERSECT "),
SetOperation::SETOP_EXCEPT => buffer.push_str(" EXCEPT "),
}
if self.all {
buffer.push_str("ALL ");
}
let right_parenthesis = need_parenthesis(right);
if right_parenthesis {
buffer.push('(');
}
(**right).build(buffer)?;
if right_parenthesis {
buffer.push(')');
}
}
_ => return Err(SqlError::Unsupported("Unsupported select type".into())),
}
if let Some(ref sort) = self.sort_clause {
buffer.push(' ');
SortClause(sort).build(buffer)?;
}
if let Some(ref limit) = self.limit_count {
let ties = match *self.limit_option {
LimitOption::LIMIT_OPTION_DEFAULT => false, LimitOption::LIMIT_OPTION_COUNT => {
if !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("LIMIT ");
false
}
LimitOption::LIMIT_OPTION_WITH_TIES => {
if !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("FETCH FIRST ");
true
}
};
let all = if let Node::A_Const(ref value) = **limit {
matches!(value, ConstValue::Null)
} else {
false
};
if all {
buffer.push_str("ALL");
} else {
if let Node::A_Expr(ref expr) = **limit {
buffer.push('(');
expr.build_with_context(buffer, Context::None)?;
buffer.push(')');
} else {
limit.build(buffer)?;
}
}
if ties {
buffer.push_str(" ROWS WITH TIES")
}
}
if let Some(ref offset) = self.limit_offset {
if !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("OFFSET ");
Expr(offset).build(buffer)?;
}
if let Some(ref locking) = self.locking_clause {
for (index, clause) in iter_only!(locking, Node::LockingClause).enumerate() {
if index > 0 {
buffer.push(' ');
}
clause.build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for SortBy {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let node = must!(self.node);
Expr(node).build(buffer)?;
match *self.sortby_dir {
SortByDir::SORTBY_DEFAULT => {}
SortByDir::SORTBY_ASC => buffer.push_str(" ASC"),
SortByDir::SORTBY_DESC => buffer.push_str(" DESC"),
SortByDir::SORTBY_USING => {
buffer.push_str(" USING ");
let use_op = must!(self.use_op);
QualifiedOperator(use_op).build(buffer)?;
}
}
match *self.sortby_nulls {
SortByNulls::SORTBY_NULLS_DEFAULT => {}
SortByNulls::SORTBY_NULLS_FIRST => buffer.push_str(" NULLS FIRST"),
SortByNulls::SORTBY_NULLS_LAST => buffer.push_str(" NULLS LAST"),
}
Ok(())
}
}
impl SqlBuilder for TableLikeClause {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let relation = must!(self.relation);
buffer.push_str("LIKE ");
(**relation).build_with_context(buffer, Context::None)?;
if self.options == TableLikeOption::CREATE_TABLE_LIKE_ALL as u32 {
buffer.push_str(" INCLUDING ALL");
} else {
if self.options & TableLikeOption::CREATE_TABLE_LIKE_COMMENTS as u32 > 0 {
buffer.push_str(" INCLUDING COMMENTS");
}
if self.options & TableLikeOption::CREATE_TABLE_LIKE_CONSTRAINTS as u32 > 0 {
buffer.push_str(" INCLUDING CONSTRAINTS");
}
if self.options & TableLikeOption::CREATE_TABLE_LIKE_DEFAULTS as u32 > 0 {
buffer.push_str(" INCLUDING DEFAULTS");
}
if self.options & TableLikeOption::CREATE_TABLE_LIKE_IDENTITY as u32 > 0 {
buffer.push_str(" INCLUDING IDENTITY");
}
if self.options & TableLikeOption::CREATE_TABLE_LIKE_GENERATED as u32 > 0 {
buffer.push_str(" INCLUDING GENERATED");
}
if self.options & TableLikeOption::CREATE_TABLE_LIKE_INDEXES as u32 > 0 {
buffer.push_str(" INCLUDING INDEXES");
}
if self.options & TableLikeOption::CREATE_TABLE_LIKE_STATISTICS as u32 > 0 {
buffer.push_str(" INCLUDING STATISTICS");
}
if self.options & TableLikeOption::CREATE_TABLE_LIKE_STORAGE as u32 > 0 {
buffer.push_str(" INCLUDING STORAGE");
}
}
Ok(())
}
}
impl SqlBuilder for TransactionStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match *self.kind {
TransactionStmtKind::TRANS_STMT_BEGIN => {
buffer.push_str("BEGIN");
if let Some(ref options) = self.options {
buffer.push(' ');
TransactionModeList(options).build(buffer)?;
}
}
TransactionStmtKind::TRANS_STMT_START => {
buffer.push_str("START TRANSACTION");
if let Some(ref options) = self.options {
buffer.push(' ');
TransactionModeList(options).build(buffer)?;
}
}
TransactionStmtKind::TRANS_STMT_COMMIT => {
buffer.push_str("COMMIT");
if self.chain {
buffer.push_str(" AND CHAIN")
}
}
TransactionStmtKind::TRANS_STMT_ROLLBACK => {
buffer.push_str("ROLLBACK");
if self.chain {
buffer.push_str(" AND CHAIN")
}
}
TransactionStmtKind::TRANS_STMT_SAVEPOINT => {
buffer.push_str("SAVEPOINT ");
buffer.push_str("e_identifier(must!(self.savepoint_name)));
}
TransactionStmtKind::TRANS_STMT_RELEASE => {
buffer.push_str("RELEASE ");
buffer.push_str("e_identifier(must!(self.savepoint_name)));
}
TransactionStmtKind::TRANS_STMT_ROLLBACK_TO => {
buffer.push_str("ROLLBACK TO SAVEPOINT ");
buffer.push_str("e_identifier(must!(self.savepoint_name)));
}
TransactionStmtKind::TRANS_STMT_PREPARE => {
buffer.push_str("PREPARE TRANSACTION ");
StringLiteral(must!(self.gid)).build(buffer)?;
}
TransactionStmtKind::TRANS_STMT_COMMIT_PREPARED => {
buffer.push_str("COMMIT PREPARED ");
StringLiteral(must!(self.gid)).build(buffer)?;
}
TransactionStmtKind::TRANS_STMT_ROLLBACK_PREPARED => {
buffer.push_str("ROLLBACK PREPARED ");
StringLiteral(must!(self.gid)).build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for TriggerTransition {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.name);
if self.is_new {
buffer.push_str("NEW ");
} else {
buffer.push_str("OLD ");
}
if self.is_table {
buffer.push_str("TABLE ");
} else {
buffer.push_str("ROW ");
}
buffer.push_str("e_identifier(name));
Ok(())
}
}
impl SqlBuilder for TypeCast {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let arg = must!(self.arg);
let type_name = must!(self.type_name);
let mut parenthesis = false;
match &**arg {
Node::A_Expr(_expr) => {
buffer.push_str("CAST(");
Expr(arg).build(buffer)?;
buffer.push_str(" AS ");
type_name.build(buffer)?;
buffer.push(')');
return Ok(());
}
Node::A_Const(value) => {
let names = must!(type_name.names);
let names = node_vec_to_string_vec(names);
if names.len() == 2 && names[0].eq("pg_catalog") {
let ty = names[1];
if ty.eq("bpchar") && type_name.typmods.is_none() {
buffer.push_str("char ");
value.build(buffer)?;
return Ok(());
}
if let ConstValue::Bool(value) = value {
if *value {
buffer.push_str("true");
} else {
buffer.push_str("false");
}
return Ok(());
}
}
match value {
ConstValue::Float(_) => parenthesis = true,
ConstValue::Integer(value) if *value < 0 => parenthesis = true,
_ => {}
}
}
_ => {}
}
if parenthesis {
buffer.push('(');
}
Expr(arg).build(buffer)?;
if parenthesis {
buffer.push(')');
}
buffer.push_str("::");
(**type_name).build(buffer)?;
Ok(())
}
}
impl SqlBuilder for TypeName {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name_nodes = must!(self.names);
let names = node_vec_to_string_vec(name_nodes);
let mut skip_typmods = false;
let empty = Vec::new();
let typmods = self.typmods.as_ref().unwrap_or(&empty);
if self.setof {
buffer.push_str("SETOF ");
}
if names.len() == 2 && names[0].eq("pg_catalog") {
let other = names[1];
match &other[..] {
"bpchar" => buffer.push_str("char"),
"varchar" => buffer.push_str("varchar"),
"numeric" => buffer.push_str("numeric"),
"bool" => buffer.push_str("boolean"),
"int2" => buffer.push_str("smallint"),
"int4" => buffer.push_str("int"),
"int8" => buffer.push_str("bigint"),
"real" | "float4" => buffer.push_str("real"),
"float8" => buffer.push_str("double precision"),
"time" => buffer.push_str("time"),
"timetz" => {
buffer.push_str("time ");
if !typmods.is_empty() {
buffer.push('(');
for (index, typmod) in typmods.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
SignedIConst(typmod).build(buffer)?;
}
buffer.push(')');
}
buffer.push_str("with time zone");
skip_typmods = true;
}
"timestamp" => buffer.push_str("timestamp"),
"timestamptz" => {
buffer.push_str("timestamp ");
if !typmods.is_empty() {
buffer.push('(');
for (index, typmod) in typmods.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
SignedIConst(typmod).build(buffer)?;
}
buffer.push(')');
}
buffer.push_str("with time zone");
skip_typmods = true;
}
"interval" if typmods.is_empty() => buffer.push_str("interval"),
"interval" if !typmods.is_empty() => {
let fields = *const_integer!(typmods[0]);
buffer.push_str("interval");
match fields {
constants::interval::YEAR => buffer.push_str(" year"),
constants::interval::MONTH => buffer.push_str(" month"),
constants::interval::DAY => buffer.push_str(" day"),
constants::interval::HOUR => buffer.push_str(" hour"),
constants::interval::MINUTE => buffer.push_str(" minute"),
constants::interval::SECOND => buffer.push_str(" second"),
constants::interval::YEAR_MONTH => buffer.push_str(" year to month"),
constants::interval::DAY_HOUR => buffer.push_str(" day to hour"),
constants::interval::DAY_HOUR_MINUTE => buffer.push_str(" day to minute"),
constants::interval::DAY_HOUR_MINUTE_SECOND => {
buffer.push_str(" day to second")
}
constants::interval::HOUR_MINUTE => buffer.push_str(" hour to minute"),
constants::interval::HOUR_MINUTE_SECOND => {
buffer.push_str(" hour to second")
}
constants::interval::MINUTE_SECOND => buffer.push_str(" minute to second"),
constants::interval::FULL_RANGE => {} unexpected => {
return Err(SqlError::Unsupported(format!(
"Unexpected interval: {}",
unexpected
)));
}
}
if let Some(ref mods) = self.typmods {
if mods.len() == 2 {
let value = *const_integer!(mods[1]);
if value != constants::interval::FULL_PRECISION {
buffer.push_str(&format!("({})", value))
} else {
return Err(SqlError::Unsupported(
"FULL_PRECISION for typmods".into(),
));
}
}
}
skip_typmods = true;
}
name => buffer.push_str(&format!("pg_catalog.{}", name)),
}
} else {
AnyName(name_nodes).build(buffer)?;
}
if !typmods.is_empty() && !skip_typmods {
buffer.push('(');
for (index, typ) in typmods.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
match typ {
Node::A_Const(val) => val.build(buffer)?,
Node::ParamRef(param_ref) => param_ref.build(buffer)?,
Node::ColumnRef(column_ref) => column_ref.build(buffer)?,
ty => return Err(SqlError::UnexpectedNodeType(ty.name())),
}
}
buffer.push(')');
}
if let Some(ref bounds) = self.array_bounds {
for bound in bounds {
buffer.push('[');
match &bound {
Node::Integer { ival: Some(value) } if *value >= 0 => {
buffer.push_str(&(*value).to_string())
}
_ => {} }
buffer.push(']');
}
}
if self.pct_type {
buffer.push_str("%type");
}
Ok(())
}
}
impl SqlBuilder for UpdateStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let relation = must!(self.relation);
if let Some(ref with) = self.with_clause {
(**with).build(buffer)?;
buffer.push(' ');
}
buffer.push_str("UPDATE ");
(**relation).build_with_context(buffer, Context::None)?;
if let Some(ref list) = self.target_list {
if !list.is_empty() {
buffer.push_str(" SET ");
SetClauseList(list).build(buffer)?;
}
}
if let Some(ref from) = self.from_clause {
buffer.push(' ');
FromClause(from).build(buffer)?;
}
if let Some(ref clause) = self.where_clause {
buffer.push(' ');
WhereClause(clause).build(buffer)?;
}
if let Some(ref returning) = self.returning_list {
if !returning.is_empty() {
buffer.push_str(" RETURNING ");
TargetList(returning).build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for VacuumStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if self.is_vacuumcmd {
buffer.push_str("VACUUM");
} else {
buffer.push_str("ANALYZE");
}
if let Some(ref options) = self.options {
if !options.is_empty() {
buffer.push_str(" (");
for (index, option) in iter_only!(options, Node::DefElem).enumerate() {
if index > 0 {
buffer.push_str(", ");
}
GenericDefElemName(must!(option.defname)).build(buffer)?;
if let Some(ref arg) = option.arg {
buffer.push(' ');
match &**arg {
Node::Integer { .. } | Node::Float { .. } => {
NumericOnly(arg).build(buffer)?
}
Node::String { sval: Some(value) } => {
BooleanOrString(value).build(buffer)?
}
unexpected => {
return Err(SqlError::UnexpectedNodeType(unexpected.name()));
}
}
}
}
buffer.push(')');
}
}
if let Some(ref rels) = self.rels {
for (index, rel) in iter_only!(rels, Node::VacuumRelation).enumerate() {
if index > 0 {
buffer.push_str(", ");
} else {
buffer.push(' ');
}
must!(rel.relation).build_with_context(buffer, Context::None)?;
if let Some(ref cols) = rel.va_cols {
if !cols.is_empty() {
buffer.push('(');
for (sub_index, col) in cols.iter().enumerate() {
if sub_index > 0 {
buffer.push_str(", ");
}
buffer.push_str("e_identifier(string_value!(col)));
}
buffer.push(')');
}
}
}
}
Ok(())
}
}
impl SqlBuilder for VariableSetStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match *self.kind {
VariableSetKind::VAR_SET_VALUE => {
buffer.push_str("SET ");
if self.is_local {
buffer.push_str("LOCAL ");
}
if let Some(ref name) = self.name {
VarName(name).build(buffer)?;
}
buffer.push_str(" TO ");
if let Some(ref args) = self.args {
VarList(args).build(buffer)?;
}
}
VariableSetKind::VAR_SET_DEFAULT => {
buffer.push_str("SET ");
if self.is_local {
buffer.push_str("LOCAL ");
}
if let Some(ref name) = self.name {
VarName(name).build(buffer)?;
}
buffer.push_str(" TO DEFAULT");
}
VariableSetKind::VAR_SET_CURRENT => {
buffer.push_str("SET ");
if self.is_local {
buffer.push_str("LOCAL ");
}
if let Some(ref name) = self.name {
VarName(name).build(buffer)?;
}
buffer.push_str(" FROM CURRENT");
}
VariableSetKind::VAR_SET_MULTI => {
let name = must!(self.name);
buffer.push_str("SET ");
if self.is_local {
buffer.push_str("LOCAL ");
}
match &name[..] {
"TRANSACTION" => {
buffer.push_str("TRANSACTION ");
let args = must!(self.args);
TransactionModeList(args).build(buffer)?;
}
"SESSION CHARACTERISTICS" => {
buffer.push_str("SESSION CHARACTERISTICS AS TRANSACTION ");
let args = must!(self.args);
TransactionModeList(args).build(buffer)?;
}
"TRANSACTION SNAPSHOT" => {
buffer.push_str("TRANSACTION SNAPSHOT ");
let args = must!(self.args);
if args.is_empty() {
return Err(SqlError::Missing("args".into()));
}
let literal = const_string!(args[0]);
StringLiteral(literal).build(buffer)?;
}
unsupported => {
return Err(SqlError::Unsupported(format!(
"Unsupported set type: {}",
unsupported
)));
}
}
}
VariableSetKind::VAR_RESET => {
buffer.push_str("RESET ");
if let Some(ref name) = self.name {
VarName(name).build(buffer)?;
}
}
VariableSetKind::VAR_RESET_ALL => buffer.push_str("RESET ALL"),
}
Ok(())
}
}
impl SqlBuilder for ViewStmt {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let view = must!(self.view);
buffer.push_str("CREATE ");
if self.replace {
buffer.push_str("OR REPLACE ");
}
if let Some(persistence) = persistence_from_code(view.relpersistence) {
buffer.push_str(persistence);
buffer.push(' ');
}
buffer.push_str("VIEW ");
(**view).build_with_context(buffer, Context::None)?;
if let Some(ref aliases) = self.aliases {
if !aliases.is_empty() {
buffer.push_str(" (");
ColumnList(aliases).build(buffer)?;
buffer.push(')');
}
}
if let Some(ref options) = self.options {
buffer.push(' ');
OptWith(options).build(buffer)?;
}
if !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("AS ");
if let Some(ref query) = self.query {
node!(**query, Node::SelectStmt).build(buffer)?;
}
match *self.with_check_option {
ViewCheckOption::NO_CHECK_OPTION => {}
ViewCheckOption::LOCAL_CHECK_OPTION => buffer.push_str(" WITH LOCAL CHECK OPTION"),
ViewCheckOption::CASCADED_CHECK_OPTION => buffer.push_str(" WITH CHECK OPTION"),
}
Ok(())
}
}
impl SqlBuilder for WindowDef {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push('(');
if let Some(ref ref_name) = self.refname {
buffer.push_str("e_identifier(ref_name));
}
if let Some(ref partition) = self.partition_clause {
if !partition.is_empty() {
if !buffer.ends_with('(') && !buffer.ends_with(' ') {
buffer.push(' ');
}
buffer.push_str("PARTITION BY ");
ExprList(partition).build(buffer)?;
}
}
if let Some(ref sort) = self.order_clause {
if !buffer.ends_with('(') && !buffer.ends_with(' ') {
buffer.push(' ');
}
SortClause(sort).build(buffer)?;
}
if self.frame_options & constants::FRAMEOPTION_NONDEFAULT > 0 {
if self.frame_options & constants::FRAMEOPTION_RANGE > 0 {
buffer.push_str(" RANGE");
} else if self.frame_options & constants::FRAMEOPTION_ROWS > 0 {
buffer.push_str(" ROWS");
} else if self.frame_options & constants::FRAMEOPTION_GROUPS > 0 {
buffer.push_str(" GROUPS");
}
if self.frame_options & constants::FRAMEOPTION_BETWEEN > 0 {
buffer.push_str(" BETWEEN");
}
if self.frame_options & constants::FRAMEOPTION_START_UNBOUNDED_PRECEDING > 0 {
buffer.push_str(" UNBOUNDED PRECEDING");
} else if self.frame_options & constants::FRAMEOPTION_START_UNBOUNDED_FOLLOWING > 0 {
return Err(SqlError::Unsupported(
"FRAMEOPTION_START_UNBOUNDED_FOLLOWING disallowed".into(),
));
} else if self.frame_options & constants::FRAMEOPTION_START_CURRENT_ROW > 0 {
buffer.push_str(" CURRENT ROW");
} else if self.frame_options & constants::FRAMEOPTION_START_OFFSET_PRECEDING > 0 {
let start_offset = must!(self.start_offset);
buffer.push(' ');
Expr(start_offset).build(buffer)?;
buffer.push_str(" PRECEDING");
} else if self.frame_options & constants::FRAMEOPTION_START_OFFSET_FOLLOWING > 0 {
let start_offset = must!(self.start_offset);
buffer.push(' ');
Expr(start_offset).build(buffer)?;
buffer.push_str(" FOLLOWING");
}
if self.frame_options & constants::FRAMEOPTION_BETWEEN > 0 {
buffer.push_str(" AND");
if self.frame_options & constants::FRAMEOPTION_END_UNBOUNDED_PRECEDING > 0 {
return Err(SqlError::Unsupported(
"FRAMEOPTION_END_UNBOUNDED_PRECEDING disallowed".into(),
));
} else if self.frame_options & constants::FRAMEOPTION_END_UNBOUNDED_FOLLOWING > 0 {
buffer.push_str(" UNBOUNDED FOLLOWING");
} else if self.frame_options & constants::FRAMEOPTION_END_CURRENT_ROW > 0 {
buffer.push_str(" CURRENT ROW");
} else if self.frame_options & constants::FRAMEOPTION_END_OFFSET_PRECEDING > 0 {
let end_offset = must!(self.end_offset);
buffer.push(' ');
Expr(end_offset).build(buffer)?;
buffer.push_str(" PRECEDING");
} else if self.frame_options & constants::FRAMEOPTION_END_OFFSET_FOLLOWING > 0 {
let end_offset = must!(self.end_offset);
buffer.push(' ');
Expr(end_offset).build(buffer)?;
buffer.push_str(" FOLLOWING");
}
}
if self.frame_options & constants::FRAMEOPTION_EXCLUDE_CURRENT_ROW > 0 {
buffer.push_str(" EXCLUDE CURRENT ROW");
} else if self.frame_options & constants::FRAMEOPTION_EXCLUDE_GROUP > 0 {
buffer.push_str(" EXCLUDE GROUP");
} else if self.frame_options & constants::FRAMEOPTION_EXCLUDE_TIES > 0 {
buffer.push_str(" EXCLUDE TIES");
}
}
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for WithClause {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("WITH ");
if self.recursive {
buffer.push_str("RECURSIVE ");
}
if let Some(ref ctes) = self.ctes {
for (index, node) in ctes.iter().enumerate() {
if index > 0 {
buffer.push_str(", ");
}
let cte = node!(node, Node::CommonTableExpr);
cte.build(buffer)?;
}
}
Ok(())
}
}
impl SqlBuilder for XmlSerialize {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("xmlserialize(");
match *self.xmloption {
XmlOptionType::XMLOPTION_DOCUMENT => buffer.push_str("document "),
XmlOptionType::XMLOPTION_CONTENT => buffer.push_str("content "),
}
if let Some(ref expr) = self.expr {
Expr(expr).build(buffer)?;
}
buffer.push_str(" AS ");
if let Some(ref type_name) = self.type_name {
(**type_name).build(buffer)?;
}
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for Alias {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.aliasname);
buffer.push_str("e_identifier(name));
if let Some(ref columns) = self.colnames {
if !columns.is_empty() {
buffer.push('(');
NameList(columns).build(buffer)?;
buffer.push(')');
}
}
Ok(())
}
}
impl SqlBuilder for BoolExpr {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let args = must!(self.args);
match *self.boolop {
BoolExprType::AND_EXPR | BoolExprType::OR_EXPR => {
let mut iter = args.iter().peekable();
while let Some(arg) = iter.next() {
let parenthesis = if let Node::BoolExpr(be) = &arg {
(*be.boolop).eq(&BoolExprType::AND_EXPR)
|| (*be.boolop).eq(&BoolExprType::OR_EXPR)
} else {
false
};
if parenthesis {
buffer.push('(');
}
Expr(arg).build(buffer)?;
if parenthesis {
buffer.push(')');
}
if iter.peek().is_some() {
buffer.push_str(&format!(" {} ", *self.boolop));
}
}
}
BoolExprType::NOT_EXPR => {
if args.len() != 1 {
return Err(SqlError::Unsupported("args.len() != 1".into()));
}
let arg = &args[0];
let parenthesis = if let Node::BoolExpr(b) = arg {
(*b.boolop).eq(&BoolExprType::AND_EXPR)
|| (*b.boolop).eq(&BoolExprType::OR_EXPR)
} else {
false
};
buffer.push_str("NOT ");
if parenthesis {
buffer.push('(');
}
Expr(arg).build(buffer)?;
if parenthesis {
buffer.push('(');
}
}
}
Ok(())
}
}
impl SqlBuilder for BooleanTest {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let arg = must!(self.arg);
Expr(arg).build(buffer)?;
match *self.booltesttype {
BoolTestType::IS_TRUE => buffer.push_str(" IS TRUE"),
BoolTestType::IS_NOT_TRUE => buffer.push_str(" IS NOT TRUE"),
BoolTestType::IS_FALSE => buffer.push_str(" IS FALSE"),
BoolTestType::IS_NOT_FALSE => buffer.push_str(" IS NOT FALSE"),
BoolTestType::IS_UNKNOWN => buffer.push_str(" IS UNKNOWN"),
BoolTestType::IS_NOT_UNKNOWN => buffer.push_str(" IS NOT UNKNOWN"),
}
Ok(())
}
}
impl SqlBuilder for CaseExpr {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("CASE ");
if let Some(ref arg) = self.arg {
Expr(arg).build(buffer)?;
buffer.push(' ');
}
if let Some(ref args) = self.args {
for arg in args {
node!(arg, Node::CaseWhen).build(buffer)?;
buffer.push(' ');
}
}
if let Some(ref else_clause) = self.defresult {
buffer.push_str("ELSE ");
Expr(else_clause).build(buffer)?;
buffer.push(' ');
}
buffer.push_str("END");
Ok(())
}
}
impl SqlBuilder for CaseWhen {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let expr = must!(self.expr);
let result = must!(self.result);
buffer.push_str("WHEN ");
Expr(expr).build(buffer)?;
buffer.push_str(" THEN ");
Expr(result).build(buffer)
}
}
impl SqlBuilder for CoalesceExpr {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let args = must!(self.args);
buffer.push_str("COALESCE(");
ExprList(args).build(buffer)?;
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for CurrentOfExpr {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let name = must!(self.cursor_name);
buffer.push_str("CURRENT OF ");
buffer.push_str("e_identifier(name));
Ok(())
}
}
impl SqlBuilder for GroupingFunc {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("GROUPING(");
if let Some(ref args) = self.args {
ExprList(args).build(buffer)?;
}
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for IntoClause {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let rel = must!(self.rel);
(**rel).build_with_context(buffer, Context::None)?;
if let Some(ref column_names) = self.col_names {
if !column_names.is_empty() {
buffer.push('(');
ColumnList(column_names).build(buffer)?;
buffer.push(')');
}
}
if let Some(ref method) = self.access_method {
buffer.push_str(" USING ");
buffer.push_str("e_identifier(method));
}
if let Some(ref options) = self.options {
buffer.push(' ');
OptWith(options).build(buffer)?;
}
match *self.on_commit {
OnCommitAction::ONCOMMIT_NOOP => {}
OnCommitAction::ONCOMMIT_PRESERVE_ROWS => buffer.push_str(" ON COMMIT PRESERVE ROWS"),
OnCommitAction::ONCOMMIT_DELETE_ROWS => buffer.push_str(" ON COMMIT DELETE ROWS"),
OnCommitAction::ONCOMMIT_DROP => buffer.push_str(" ON COMMIT DROP"),
}
if let Some(ref tablespace) = self.table_space_name {
buffer.push_str(" TABLESPACE ");
buffer.push_str("e_identifier(tablespace));
}
Ok(())
}
}
impl SqlBuilder for JoinExpr {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
if self.alias.is_some() {
buffer.push('(');
}
let table_ref = must!(self.larg);
let join_ref = must!(self.rarg);
TableRef(table_ref).build(buffer)?;
buffer.push(' ');
if self.is_natural {
buffer.push_str("NATURAL ");
}
let empty = Vec::new();
let using = self.using_clause.as_ref().unwrap_or(&empty);
match *self.jointype {
JoinType::JOIN_INNER => {
if !self.is_natural && self.quals.is_none() && using.is_empty() {
buffer.push_str("CROSS ");
} else {
buffer.push_str("INNER ");
}
}
JoinType::JOIN_LEFT => buffer.push_str("LEFT "),
JoinType::JOIN_FULL => buffer.push_str("FULL "),
JoinType::JOIN_RIGHT => buffer.push_str("RIGHT "),
JoinType::JOIN_SEMI => {}
JoinType::JOIN_ANTI => {}
JoinType::JOIN_UNIQUE_OUTER => {}
JoinType::JOIN_UNIQUE_INNER => {}
JoinType::JOIN_RIGHT_ANTI => {}
}
buffer.push_str("JOIN ");
let join_parens = match **join_ref {
Node::JoinExpr(ref inner) => inner.alias.is_none(),
_ => false,
};
if join_parens {
buffer.push('(');
}
TableRef(join_ref).build(buffer)?;
if join_parens {
buffer.push(')');
}
if let Some(ref qualifiers) = self.quals {
buffer.push_str(" ON ");
Expr(qualifiers).build(buffer)?;
}
if !using.is_empty() {
buffer.push_str(" USING (");
NameList(using).build(buffer)?;
buffer.push(')');
}
if self.alias.is_some() {
buffer.push(')');
}
if let Some(ref alias) = self.alias {
(**alias).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for MinMaxExpr {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match *self.op {
MinMaxOp::IS_GREATEST => buffer.push_str("GREATEST("),
MinMaxOp::IS_LEAST => buffer.push_str("LEAST("),
}
if let Some(ref args) = self.args {
ExprList(args).build(buffer)?;
}
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for NullTest {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let arg = must!(self.arg);
Expr(arg).build(buffer)?;
match *self.nulltesttype {
NullTestType::IS_NULL => buffer.push_str(" IS NULL"),
NullTestType::IS_NOT_NULL => buffer.push_str(" IS NOT NULL"),
}
Ok(())
}
}
impl SqlBuilderWithContext for RangeVar {
fn build_with_context(&self, buffer: &mut String, context: Context) -> Result<(), SqlError> {
if !self.inh {
match context {
Context::CreateType | Context::AlterType => {}
_ => buffer.push_str("ONLY "),
}
}
if let Some(ref catalog) = self.catalogname {
buffer.push_str(&format!("{}.", quote_identifier(catalog)));
}
if let Some(ref schema) = self.schemaname {
buffer.push_str(&format!("{}.", quote_identifier(schema)));
}
if let Some(ref name) = self.relname {
buffer.push_str("e_identifier(name));
}
if let Some(ref alias) = self.alias {
if context == Context::InsertRelation {
buffer.push_str(" AS ");
} else {
buffer.push(' ');
}
(**alias).build(buffer)?;
}
Ok(())
}
}
impl SqlBuilder for RowExpr {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let args = must!(self.args);
match *self.row_format {
CoercionForm::COERCE_EXPLICIT_CALL => buffer.push_str("ROW"),
CoercionForm::COERCE_EXPLICIT_CAST => {
return Err(SqlError::Unsupported("COERCE_EXPLICIT_CAST".into()));
}
CoercionForm::COERCE_IMPLICIT_CAST => {}
CoercionForm::COERCE_SQL_SYNTAX => {}
}
buffer.push('(');
ExprList(args).build(buffer)?;
buffer.push(')');
Ok(())
}
}
impl SqlBuilder for SQLValueFunction {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match *self.op {
SQLValueFunctionOp::SVFOP_CURRENT_DATE => buffer.push_str("current_date"),
SQLValueFunctionOp::SVFOP_CURRENT_TIME => buffer.push_str("current_time"),
SQLValueFunctionOp::SVFOP_CURRENT_TIME_N => buffer.push_str("current_time"),
SQLValueFunctionOp::SVFOP_CURRENT_TIMESTAMP => buffer.push_str("current_timestamp"),
SQLValueFunctionOp::SVFOP_CURRENT_TIMESTAMP_N => buffer.push_str("current_timestamp"),
SQLValueFunctionOp::SVFOP_LOCALTIME => buffer.push_str("localtime"),
SQLValueFunctionOp::SVFOP_LOCALTIME_N => buffer.push_str("localtime"),
SQLValueFunctionOp::SVFOP_LOCALTIMESTAMP => buffer.push_str("localtimestamp"),
SQLValueFunctionOp::SVFOP_LOCALTIMESTAMP_N => buffer.push_str("localtimestamp"),
SQLValueFunctionOp::SVFOP_CURRENT_ROLE => buffer.push_str("current_role"),
SQLValueFunctionOp::SVFOP_CURRENT_USER => buffer.push_str("current_user"),
SQLValueFunctionOp::SVFOP_USER => buffer.push_str("user"),
SQLValueFunctionOp::SVFOP_SESSION_USER => buffer.push_str("session_user"),
SQLValueFunctionOp::SVFOP_CURRENT_CATALOG => buffer.push_str("current_catalog"),
SQLValueFunctionOp::SVFOP_CURRENT_SCHEMA => buffer.push_str("current_schema"),
}
if self.typmod != -1 {
buffer.push_str(&format!("({})", self.typmod));
}
Ok(())
}
}
impl SqlBuilder for SetToDefault {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
buffer.push_str("DEFAULT");
Ok(())
}
}
impl SqlBuilder for SubLink {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
let sub_select = must!(self.subselect);
match *self.sub_link_type {
SubLinkType::EXISTS_SUBLINK => {
buffer.push_str("EXISTS (");
sub_select.build(buffer)?;
buffer.push(')');
}
SubLinkType::ALL_SUBLINK => {
let test = must!(self.testexpr);
let op = must!(self.oper_name);
Expr(test).build(buffer)?;
buffer.push(' ');
SubqueryOperator(op).build(buffer)?;
buffer.push_str(" ALL (");
sub_select.build(buffer)?;
buffer.push(')');
}
SubLinkType::ANY_SUBLINK => {
let test = must!(self.testexpr);
Expr(test).build(buffer)?;
if let Some(ref op) = self.oper_name {
buffer.push(' ');
SubqueryOperator(op).build(buffer)?;
buffer.push_str(" ANY ");
} else {
buffer.push_str(" IN ");
}
buffer.push('(');
sub_select.build(buffer)?;
buffer.push(')');
}
SubLinkType::ROWCOMPARE_SUBLINK => {
return Err(SqlError::Unsupported("ROWCOMPARE_SUBLINK".into()));
}
SubLinkType::EXPR_SUBLINK => {
buffer.push('(');
sub_select.build(buffer)?;
buffer.push(')');
}
SubLinkType::MULTIEXPR_SUBLINK => {
return Err(SqlError::Unsupported("MULTIEXPR_SUBLINK".into()));
}
SubLinkType::ARRAY_SUBLINK => {
buffer.push_str("ARRAY(");
sub_select.build(buffer)?;
buffer.push(')');
}
SubLinkType::CTE_SUBLINK => {
return Err(SqlError::Unsupported("CTE_SUBLINK".into()));
}
}
Ok(())
}
}
impl SqlBuilder for XmlExpr {
fn build(&self, buffer: &mut String) -> Result<(), SqlError> {
match *self.op {
XmlExprOp::IS_XMLCONCAT => {
buffer.push_str("xmlconcat(");
if let Some(ref args) = self.args {
ExprList(args).build(buffer)?;
}
buffer.push(')');
}
XmlExprOp::IS_XMLELEMENT => {
buffer.push_str("xmlelement(name ");
if let Some(ref name) = self.name {
buffer.push_str("e_identifier(name));
}
if let Some(ref named_args) = self.named_args {
buffer.push_str(", xmlattributes(");
XmlAttributeList(named_args).build(buffer)?;
buffer.push(')');
}
if let Some(ref args) = self.args {
buffer.push_str(", ");
ExprList(args).build(buffer)?;
}
buffer.push(')');
}
XmlExprOp::IS_XMLFOREST => {
buffer.push_str("xmlforest(");
if let Some(ref named_args) = self.named_args {
XmlAttributeList(named_args).build(buffer)?;
}
buffer.push(')');
}
XmlExprOp::IS_XMLPARSE => {
let args = must!(self.args);
if args.len() != 2 {
return Err(SqlError::Unsupported("args.len() != 2".into()));
}
buffer.push_str("xmlparse(");
match *self.xmloption {
XmlOptionType::XMLOPTION_DOCUMENT => buffer.push_str("document "),
XmlOptionType::XMLOPTION_CONTENT => buffer.push_str("content "),
}
Expr(&args[0]).build(buffer)?;
if let Node::TypeCast(ref tc) = args[1] {
if let Some(ref inner) = tc.arg {
if let Node::Boolean {
boolval: Some(value),
} = **inner
{
if value {
buffer.push_str(" PRESERVE WHITESPACE");
}
}
}
}
buffer.push(')');
}
XmlExprOp::IS_XMLPI => {
buffer.push_str("xmlpi(name ");
if let Some(ref name) = self.name {
buffer.push_str("e_identifier(name));
}
if let Some(ref args) = self.args {
if !args.is_empty() {
buffer.push_str(", ");
Expr(&args[0]).build(buffer)?;
}
}
buffer.push(')');
}
XmlExprOp::IS_XMLROOT => {
let mut args = must!(self.args).iter();
let arg = args
.next()
.ok_or_else(|| SqlError::Missing("Missing element (1)".into()))?;
buffer.push_str("xmlroot(");
Expr(arg).build(buffer)?;
buffer.push_str(", version ");
let arg = args
.next()
.ok_or_else(|| SqlError::Missing("Missing element (2)".into()))?;
match arg {
Node::A_Const(value) => {
if let ConstValue::Null = value {
buffer.push_str("NO VALUE");
} else {
Expr(arg).build(buffer)?;
}
}
other => Expr(other).build(buffer)?,
}
let arg = args
.next()
.ok_or_else(|| SqlError::Missing("Missing element (3)".into()))?;
let value = *const_integer!(arg);
if value == 0 {
buffer.push_str(", STANDALONE YES");
} else if value == 1 {
buffer.push_str(", STANDALONE NO");
} else if value == 2 {
buffer.push_str(", STANDALONE NO VALUE");
}
buffer.push(')');
}
XmlExprOp::IS_XMLSERIALIZE => {
}
XmlExprOp::IS_DOCUMENT => {
let args = must!(self.args);
if args.len() != 1 {
return Err(SqlError::Unsupported("args.len() != 1".into()));
}
Expr(&args[0]).build(buffer)?;
buffer.push_str(" IS DOCUMENT");
}
}
Ok(())
}
}