Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 28 additions & 67 deletions benches/translation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,20 +159,23 @@ fn bench_rls_translation(c: &mut Criterion) {
group.finish();
}

fn bench_select_statements(c: &mut Criterion) {
/// Benchmarks parsing and translating each of `statements` against the
/// statement schema, each id under `function` when given.
fn bench_statements(
c: &mut Criterion,
group_name: &str,
statements: &[(&str, &str)],
function: Option<&str>,
) {
let options = Pg2SqliteOptions::default();
let schema = statement_schema();
let mut group = c.benchmark_group("statement/select");

let statements: &[(&str, &str)] = &[
("simple", SELECT_SIMPLE),
("join", SELECT_JOIN),
("subquery", SELECT_SUBQUERY),
("cte", SELECT_CTE),
];

let mut group = c.benchmark_group(group_name);
for (name, sql) in statements {
group.bench_with_input(BenchmarkId::from_parameter(name), *sql, |b, sql| {
let id = match function {
Some(function) => BenchmarkId::new(function, name),
None => BenchmarkId::from_parameter(name),
};
group.bench_with_input(id, *sql, |b, sql| {
b.iter(|| {
let parsed = Pg2Sqlite::default().sql(black_box(sql)).unwrap();
black_box(parsed.translate_with_schema(&schema, &options).unwrap())
Expand All @@ -182,71 +185,38 @@ fn bench_select_statements(c: &mut Criterion) {
group.finish();
}

fn bench_insert_statements(c: &mut Criterion) {
let options = Pg2SqliteOptions::default();
let schema = statement_schema();
let mut group = c.benchmark_group("statement/insert");
fn bench_select_statements(c: &mut Criterion) {
let statements: &[(&str, &str)] = &[
("simple", SELECT_SIMPLE),
("join", SELECT_JOIN),
("subquery", SELECT_SUBQUERY),
("cte", SELECT_CTE),
];
bench_statements(c, "statement/select", statements, None);
}

fn bench_insert_statements(c: &mut Criterion) {
let statements: &[(&str, &str)] = &[
("simple", INSERT_SIMPLE),
("multi_row", INSERT_MULTI_ROW),
("select", INSERT_SELECT),
("on_conflict", INSERT_ON_CONFLICT),
];

for (name, sql) in statements {
group.bench_with_input(BenchmarkId::from_parameter(name), *sql, |b, sql| {
b.iter(|| {
let parsed = Pg2Sqlite::default().sql(black_box(sql)).unwrap();
black_box(parsed.translate_with_schema(&schema, &options).unwrap())
});
});
}
group.finish();
bench_statements(c, "statement/insert", statements, None);
}

fn bench_update_statements(c: &mut Criterion) {
let options = Pg2SqliteOptions::default();
let schema = statement_schema();
let mut group = c.benchmark_group("statement/update");

let statements: &[(&str, &str)] =
&[("simple", UPDATE_SIMPLE), ("multi_column", UPDATE_MULTI_COLUMN)];

for (name, sql) in statements {
group.bench_with_input(BenchmarkId::from_parameter(name), *sql, |b, sql| {
b.iter(|| {
let parsed = Pg2Sqlite::default().sql(black_box(sql)).unwrap();
black_box(parsed.translate_with_schema(&schema, &options).unwrap())
});
});
}
group.finish();
bench_statements(c, "statement/update", statements, None);
}

fn bench_delete_statements(c: &mut Criterion) {
let options = Pg2SqliteOptions::default();
let schema = statement_schema();
let mut group = c.benchmark_group("statement/delete");

let statements: &[(&str, &str)] = &[("simple", DELETE_SIMPLE), ("subquery", DELETE_SUBQUERY)];

for (name, sql) in statements {
group.bench_with_input(BenchmarkId::from_parameter(name), *sql, |b, sql| {
b.iter(|| {
let parsed = Pg2Sqlite::default().sql(black_box(sql)).unwrap();
black_box(parsed.translate_with_schema(&schema, &options).unwrap())
});
});
}
group.finish();
bench_statements(c, "statement/delete", statements, None);
}

fn bench_translation_samples(c: &mut Criterion) {
let options = Pg2SqliteOptions::default();
let schema = statement_schema();
let mut group = c.benchmark_group("translation_samples");

let statements: &[(&str, &str)] = &[
("select_simple", SELECT_SIMPLE),
("select_join", SELECT_JOIN),
Expand All @@ -261,16 +231,7 @@ fn bench_translation_samples(c: &mut Criterion) {
"CREATE TABLE t (id SERIAL PRIMARY KEY, name TEXT NOT NULL, active BOOLEAN, created_at TIMESTAMPTZ);",
),
];

for (name, sql) in statements {
group.bench_with_input(BenchmarkId::new("pg2sqlite", name), *sql, |b, sql| {
b.iter(|| {
let parsed = Pg2Sqlite::default().sql(black_box(sql)).unwrap();
black_box(parsed.translate_with_schema(&schema, &options).unwrap())
});
});
}
group.finish();
bench_statements(c, "translation_samples", statements, Some("pg2sqlite"));
}

const QUERY_SCHEMA: &str = "CREATE TABLE nums (n INTEGER NOT NULL);";
Expand Down
21 changes: 5 additions & 16 deletions src/history/rebind/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,10 @@ impl Planner<'_> {
&& let sqlparser::ast::OrderByKind::Expressions(keys) = &order_by.kind
&& let Some(outputs) = scope.scope_for_query(query)
{
let mut listed = Vec::new();
if let SetExpr::Select(select) = query.body.as_ref() {
for table in &select.from {
self.list(&table.relation, &mut listed)?;
for join in &table.joins {
self.list(&join.relation, &mut listed)?;
}
}
}
let listed = match query.body.as_ref() {
SetExpr::Select(select) => self.list_from(select)?,
_ => Vec::new(),
};
self.frames.push(listed);
let mut result = Ok(());
for key in keys {
Expand Down Expand Up @@ -144,13 +139,7 @@ impl Planner<'_> {
header: Header,
) -> Result<(), ConnectionError> {
let Some(inner) = scope.scope_for_select(select) else { return Ok(()) };
let mut listed = Vec::new();
for table in &select.from {
self.list(&table.relation, &mut listed)?;
for join in &table.joins {
self.list(&join.relation, &mut listed)?;
}
}
let listed = self.list_from(select)?;
self.frames.push(listed);
let result = self.select_clauses(scope, &inner, select, header);
self.frames.pop();
Expand Down
16 changes: 15 additions & 1 deletion src/history/rebind/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use sql_traits::{
structs::{IdentifierCase, ParserDB, TargetName},
traits::{ColumnLike, DatabaseLike, TableLike, ViewLike},
};
use sqlparser::ast::{Expr, Ident, ObjectName, ObjectNamePart, SelectItem, SetExpr, TableFactor};
use sqlparser::ast::{
Expr, Ident, ObjectName, ObjectNamePart, Select, SelectItem, SetExpr, TableFactor,
};

use super::Planner;
use crate::script::ConnectionError;
Expand Down Expand Up @@ -62,6 +64,18 @@ impl Planner<'_> {
self.list_as(factor, listed, false)
}

/// The relations every `FROM` item of `select` names, joins included.
pub(super) fn list_from(&self, select: &Select) -> Result<Vec<Listed>, ConnectionError> {
let mut listed = Vec::new();
for table in &select.from {
self.list(&table.relation, &mut listed)?;
for join in &table.joins {
self.list(&join.relation, &mut listed)?;
}
}
Ok(listed)
}

/// Records a written table, which no common table expression can name.
pub(super) fn list_target(
&self,
Expand Down
19 changes: 4 additions & 15 deletions src/impls/reverse_translator_impls/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ use crate::{
numeric_minor_unit_scales_of_table, translate_conflict_predicate,
translate_on_conflict_do_update, translate_returning,
},
translator_impls::insert::{for_each_insert_position, insert_target_scope},
translator_impls::insert::{
for_each_insert_position, insert_column_names, insert_target_scope,
},
},
prelude::ReverseTranslator,
};
Expand Down Expand Up @@ -249,19 +251,6 @@ fn build_upsert_on_conflict(

type ParserTable = <ParserDB as DatabaseLike>::Table;

/// Column names the INSERT targets, in value order.
fn reverse_insert_column_names(
insert: &Insert,
table: &ParserTable,
schema: &ParserDB,
) -> Result<Vec<String>, Error> {
if insert.columns.is_empty() {
Ok(table.columns(schema)?.map(|c| c.column_name().to_owned()).collect())
} else {
Ok(insert.columns.iter().filter_map(|n| last_ident(n).map(|i| i.value.clone())).collect())
}
}

/// Unscales integer literals at NUMERIC column positions back to decimal form.
///
/// Mirrors the forward `scale_numeric_literals` but divides by 10^s rather than
Expand All @@ -275,7 +264,7 @@ fn unscale_numeric_literals(
if scales.is_empty() {
return Ok(());
}
let column_names = reverse_insert_column_names(insert, table, schema)?;
let column_names = insert_column_names(insert, table, schema)?;
let Some(source) = insert.source.as_deref_mut() else { return Ok(()) };
for_each_insert_position(source.body.as_mut(), &column_names, &mut |idx, mut expr| {
if let Some(column) = column_names.get(idx)
Expand Down
11 changes: 1 addition & 10 deletions src/impls/shared_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2376,16 +2376,7 @@ fn translate_table_function_args<D: TranslationDirection>(
.iter()
.map(|arg| translate_function_arg::<D>(arg, schema, options, emit))
.collect::<Result<Vec<_>, _>>()?,
settings: args
.settings
.as_ref()
.map(|settings| {
settings
.iter()
.map(|setting| translate_setting::<D>(setting, schema, options, emit))
.collect::<Result<Vec<_>, _>>()
})
.transpose()?,
settings: translate_query_settings::<D>(args.settings.as_ref(), schema, options, emit)?,
})
}

Expand Down
25 changes: 11 additions & 14 deletions src/impls/translator_impls/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2467,6 +2467,15 @@ fn warn_ascii_only_ilike_folding(
});
}

/// `datetime(target, modifier..., 'subsec')` with its trailing fractional zeros
/// trimmed.
fn shifted_datetime(target: Expr, modifiers: &[String]) -> Expr {
let mut args = vec![target];
args.extend(modifiers.iter().map(|modifier| string_literal(modifier)));
args.push(string_literal("subsec"));
trim_trailing_zeros(simple_function_expr("datetime", args, None))
}

/// Translate a binary operation expression.
#[allow(clippy::too_many_lines)]
fn translate_binary_op(
Expand Down Expand Up @@ -3186,14 +3195,7 @@ fn translate_binary_op(
match interval_date_modifiers_scaled(interval, negating, n)? {
Some(modifiers) => {
let target = left.translate_with_warnings(schema, options, emit)?;
let mut args = vec![target];
for modifier in modifiers {
args.push(string_literal(&modifier));
}
args.push(string_literal("subsec"));
return Ok(trim_trailing_zeros(simple_function_expr(
"datetime", args, None,
)));
return Ok(shifted_datetime(target, &modifiers));
}
None => {
return Err(crate::errors::Error::forward_refusal(format!(
Expand All @@ -3217,12 +3219,7 @@ fn translate_binary_op(
match interval_date_modifiers(interval, negating)? {
Some(modifiers) => {
let target = left.translate_with_warnings(schema, options, emit)?;
let mut args = vec![target];
for modifier in modifiers {
args.push(string_literal(&modifier));
}
args.push(string_literal("subsec"));
return Ok(trim_trailing_zeros(simple_function_expr("datetime", args, None)));
return Ok(shifted_datetime(target, &modifiers));
}
None => {
// The notation was not decoded (HH:MM:SS, ISO P-form,
Expand Down
2 changes: 1 addition & 1 deletion src/impls/translator_impls/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ fn substitute_do_update_defaults(
/// order, which is what PostgreSQL fills an omitted list from. Comparison
/// against these names is case-insensitive at every caller, to match
/// PostgreSQL's identifier folding.
fn insert_column_names(
pub(crate) fn insert_column_names(
insert: &Insert,
table: &ParserTable,
schema: &ParserDB,
Expand Down
Loading