use super::*;
impl Renderer {
pub(super) fn render_stmt(&mut self, stmt: &Stmt) -> Result<()> {
match stmt {
Stmt::Select(select) => self.render_select(select),
Stmt::Set(set) => self.render_set(set),
Stmt::Insert(insert) => self.render_insert(insert),
Stmt::Update(update) => self.render_update(update),
Stmt::Delete(delete) => self.render_delete(delete),
Stmt::Merge(merge) => self.render_merge(merge),
Stmt::Raw(raw) => self.render_raw_stmt(raw),
}
}
pub(super) fn render_select(&mut self, select: &Select) -> Result<()> {
self.render_ctes(&select.ctes)?;
self.sql.push_str("SELECT ");
self.render_distinct(select)?;
self.render_projection(select)?;
self.sql.push_str(" FROM ");
self.render_source(&select.source)?;
for join in &select.joins {
self.render_join(join)?;
}
if let Some(filter) = &select.filter {
self.sql.push_str(" WHERE ");
self.render_bool(filter)?;
}
self.render_group_by(&select.group_by)?;
if let Some(having) = &select.having {
self.sql.push_str(" HAVING ");
self.render_bool(having)?;
}
self.render_order(&select.order)?;
self.render_limit(select.row_limit.as_ref());
if let Some(offset) = &select.offset {
self.sql.push_str(" OFFSET ");
self.push_param(offset.clone());
}
self.render_fetch(select.row_limit.as_ref())?;
self.render_lock(select.lock.as_ref());
Ok(())
}
pub(super) fn render_set(&mut self, set: &SetQuery) -> Result<()> {
self.sql.push('(');
self.render_stmt(&set.left)?;
self.sql.push_str(") ");
self.sql.push_str(set.operator.as_sql());
self.sql.push_str(" (");
self.render_stmt(&set.right)?;
self.sql.push(')');
self.render_order(&set.order)?;
self.render_limit(set.row_limit.as_ref());
if let Some(offset) = &set.offset {
self.sql.push_str(" OFFSET ");
self.push_param(offset.clone());
}
self.render_fetch(set.row_limit.as_ref())?;
Ok(())
}
pub(super) fn render_projection(&mut self, select: &Select) -> Result<()> {
if select.projection.is_empty() {
self.render_source_fields(&select.source);
return Ok(());
}
for (idx, item) in select.projection.iter().enumerate() {
if idx > 0 {
self.sql.push_str(", ");
}
self.render_select_item(item)?;
}
Ok(())
}
pub(super) fn render_distinct(&mut self, select: &Select) -> Result<()> {
if !select.distinct_on.is_empty() {
self.sql.push_str("DISTINCT ON (");
for (idx, expr) in select.distinct_on.iter().enumerate() {
if idx > 0 {
self.sql.push_str(", ");
}
self.render_value(expr)?;
}
self.sql.push_str(") ");
} else if select.distinct {
self.sql.push_str("DISTINCT ");
}
Ok(())
}
pub(super) fn render_select_item(&mut self, item: &SelectItem) -> Result<()> {
self.render_value(&item.expr)?;
if let Some(alias) = &item.alias {
self.sql.push_str(" AS ");
write_quoted_ident(&mut self.sql, alias);
}
Ok(())
}
pub(super) fn render_order(&mut self, order: &[crate::OrderItem]) -> Result<()> {
self.render_order_clause(" ORDER BY ", order)
}
pub(super) fn render_order_clause(
&mut self,
prefix: &str,
order: &[crate::OrderItem],
) -> Result<()> {
if order.is_empty() {
return Ok(());
}
self.sql.push_str(prefix);
self.render_order_items(order)
}
pub(super) fn render_order_items(&mut self, order: &[crate::OrderItem]) -> Result<()> {
for (idx, item) in order.iter().enumerate() {
if idx > 0 {
self.sql.push_str(", ");
}
self.render_value(&item.expr)?;
self.sql.push(' ');
self.sql.push_str(item.direction.as_sql());
if let Some(nulls) = item.nulls {
self.sql.push(' ');
self.sql.push_str(nulls.as_sql());
}
}
Ok(())
}
pub(super) fn render_limit(&mut self, row_limit: Option<&RowLimit>) {
if let Some(RowLimit::Limit(limit)) = row_limit {
self.sql.push_str(" LIMIT ");
self.push_param(limit.clone());
}
}
pub(super) fn render_fetch(&mut self, row_limit: Option<&RowLimit>) -> Result<()> {
let Some(RowLimit::Fetch(fetch)) = row_limit else {
return Ok(());
};
self.sql.push_str(" FETCH FIRST ");
self.render_value(&fetch.count)?;
self.sql.push_str(if fetch.with_ties {
" ROWS WITH TIES"
} else {
" ROWS ONLY"
});
Ok(())
}
pub(super) fn render_group_by(&mut self, group_by: &[GroupByItem]) -> Result<()> {
if group_by.is_empty() {
return Ok(());
}
self.sql.push_str(" GROUP BY ");
for (idx, item) in group_by.iter().enumerate() {
if idx > 0 {
self.sql.push_str(", ");
}
self.render_group_by_item(item)?;
}
Ok(())
}
pub(super) fn render_group_by_item(&mut self, item: &GroupByItem) -> Result<()> {
match item {
GroupByItem::Expr(expr) => self.render_value(expr),
GroupByItem::Rollup(exprs) => self.render_grouping_exprs("ROLLUP", exprs),
GroupByItem::Cube(exprs) => self.render_grouping_exprs("CUBE", exprs),
GroupByItem::GroupingSets(sets) => {
self.sql.push_str("GROUPING SETS (");
for (idx, set) in sets.iter().enumerate() {
if idx > 0 {
self.sql.push_str(", ");
}
self.sql.push('(');
for (expr_idx, expr) in set.iter().enumerate() {
if expr_idx > 0 {
self.sql.push_str(", ");
}
self.render_value(expr)?;
}
self.sql.push(')');
}
self.sql.push(')');
Ok(())
}
}
}
pub(super) fn render_grouping_exprs(&mut self, name: &str, exprs: &[ValueExpr]) -> Result<()> {
self.sql.push_str(name);
self.sql.push('(');
for (idx, expr) in exprs.iter().enumerate() {
if idx > 0 {
self.sql.push_str(", ");
}
self.render_value(expr)?;
}
self.sql.push(')');
Ok(())
}
pub(super) fn render_lock(&mut self, lock: Option<&crate::RowLock>) {
let Some(lock) = lock else {
return;
};
self.sql.push(' ');
self.sql.push_str(lock.mode.as_sql());
if !lock.of.is_empty() {
self.sql.push_str(" OF ");
for (idx, relation) in lock.of.iter().enumerate() {
if idx > 0 {
self.sql.push_str(", ");
}
write_quoted_qualified(&mut self.sql, relation);
}
}
if let Some(wait) = lock.wait.as_sql() {
self.sql.push(' ');
self.sql.push_str(wait);
}
}
}