Skip to content

Commit

Permalink
feat: Integrate sqllogoctest
Browse files Browse the repository at this point in the history
  • Loading branch information
Weijun-H committed Oct 13, 2024
1 parent e224559 commit 232badb
Show file tree
Hide file tree
Showing 12 changed files with 379 additions and 99 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 0 additions & 14 deletions tests/explain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,6 @@ async fn test_explain_fdw(#[future(awt)] s3: S3, mut conn: PgConnection) -> Resu
Ok(())
}

#[rstest]
async fn test_explain_heap(mut conn: PgConnection) -> Result<()> {
NycTripsTable::setup().execute(&mut conn);

let explain: Vec<(String,)> =
"EXPLAIN SELECT COUNT(*) FROM nyc_trips WHERE tip_amount <> 0".fetch(&mut conn);

assert!(explain[0].0.contains("Aggregate"));
assert!(explain[1].0.contains("Seq Scan on nyc_trips"));
assert!(explain[2].0.contains("Filter"));

Ok(())
}

#[rstest]
#[ignore = "EXPLAIN not fully working"]
async fn test_explain_federated(#[future(awt)] s3: S3, mut conn: PgConnection) -> Result<()> {
Expand Down
8 changes: 6 additions & 2 deletions tests/sqllogictests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ license = "AGPL-3.0"

[features]
default = ["pg17"]
pg13 = ["pgrx/pg13"]
pg14 = ["pgrx/pg14"]
pg15 = ["pgrx/pg15"]
pg16 = ["pgrx/pg16"]
pg17 = ["pgrx/pg17"]


[lib]
name = "paradedb_sqllogictest"

Expand All @@ -28,8 +33,7 @@ num_cpus = "1.13.0"
sqlparser = { workspace = true }
async-trait = "0.1.83"


[[bin]]
[[test]]
harness = false
name = "sqllogictests"
path = "bin/sqllogictests.rs"
34 changes: 18 additions & 16 deletions tests/sqllogictests/bin/sqllogictests.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
// Copyright (c) 2023-2024 Retake, Inc.
//
// This file is part of ParadeDB - Postgres for Search and Analytics
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use std::{
ffi::OsStr,
fs,
path::{Path, PathBuf},
};

use anyhow::Result;
use async_std::task::{self, block_on};
use async_std::task::block_on;
use datafusion::common::runtime::SpawnedTask;
use futures::StreamExt;
use log::info;
Expand All @@ -20,17 +37,7 @@ pub fn main() -> Result<()> {
}

async fn run_tests() -> Result<()> {
// Enable logging (e.g. set RUST_LOG=debug to see debug logs)
// env_logger::init();

// let options: Options = clap::Parser::parse();
// options.warn_on_ignored();

// Run all tests in parallel, reporting failures at the end
//
// Doing so is safe because each slt file runs with its own
// `SessionContext` and should not have side effects (like
// modifying shared state like `/tmp/`)
let errors: Vec<_> = futures::stream::iter(read_test_files()?)
.map(|test_file| {
SpawnedTask::spawn(async move {
Expand Down Expand Up @@ -110,11 +117,6 @@ async fn run_test_file(test_file: TestFile) -> Result<()> {
} = test_file;
info!("Running with ParadeDB runner: {}", path.display());

// let Some(test_ctx) = TestContext::try_new_for_test_file(&relative_path).await else {
// info!("Skipping: {}", path.display());
// return Ok(());
// };

setup_scratch_dir(&relative_path)?;
let mut runner = sqllogictest::Runner::new(|| async { Ok(ParadeDB::new().await) });

Expand Down
70 changes: 70 additions & 0 deletions tests/sqllogictests/src/conversion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) 2023-2024 Retake, Inc.
//
// This file is part of ParadeDB - Postgres for Search and Analytics
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use bigdecimal::BigDecimal;
use std::str::FromStr;

/// Represents a constant for NULL string in your database.
pub const NULL_STR: &str = "NULL";

pub(crate) fn bool_to_str(value: bool) -> String {
if value {
"true".to_string()
} else {
"false".to_string()
}
}

pub(crate) fn varchar_to_str(value: &str) -> String {
if value.is_empty() {
"(empty)".to_string()
} else {
value.trim_end_matches('\n').to_string()
}
}

pub(crate) fn f32_to_str(value: f32) -> String {
if value.is_nan() {
// The sign of NaN can be different depending on platform.
// So the string representation of NaN ignores the sign.
"NaN".to_string()
} else if value == f32::INFINITY {
"Infinity".to_string()
} else if value == f32::NEG_INFINITY {
"-Infinity".to_string()
} else {
big_decimal_to_str(BigDecimal::from_str(&value.to_string()).unwrap())
}
}

pub(crate) fn f64_to_str(value: f64) -> String {
if value.is_nan() {
// The sign of NaN can be different depending on platform.
// So the string representation of NaN ignores the sign.
"NaN".to_string()
} else if value == f64::INFINITY {
"Infinity".to_string()
} else if value == f64::NEG_INFINITY {
"-Infinity".to_string()
} else {
big_decimal_to_str(BigDecimal::from_str(&value.to_string()).unwrap())
}
}

pub(crate) fn big_decimal_to_str(value: BigDecimal) -> String {
value.round(12).normalized().to_string()
}
38 changes: 24 additions & 14 deletions tests/sqllogictests/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@
// We duplicated because the paradedb repo may use a different version of pgrx than pg_analytics, but eventually we should
// move this into a separate crate without any dependencies on pgrx.

use crate::normalize::convert_rows;
use crate::normalize::convert_types;
use async_std::prelude::Stream;
use async_std::stream::StreamExt;
use async_std::task::block_on;
use async_trait::async_trait;
use bytes::Bytes;
use datafusion::arrow::{datatypes::SchemaRef, record_batch::RecordBatch};
use sqllogictest::DBOutput;
use sqlx::Row;
use sqlx::{
postgres::PgRow,
testing::{TestArgs, TestContext, TestSupport},
Expand Down Expand Up @@ -114,6 +117,13 @@ where
})
}

fn fetch_dynamic_result(
self,
connection: &mut PgConnection,
) -> Result<Vec<PgRow>, sqlx::Error> {
block_on(async { sqlx::query(self.as_ref()).fetch_all(connection).await })
}

/// A convenient helper for processing PgRow results from Postgres into a DataFusion RecordBatch.
/// It's important to note that the retrieved RecordBatch may not necessarily have the same
/// column order as your Postgres table, or parquet file in a foreign table.
Expand Down Expand Up @@ -208,11 +218,6 @@ impl sqllogictest::AsyncDB for ParadeDB {
type ColumnType = DFColumnType;

async fn run(&mut self, sql: &str) -> Result<DBOutput<Self::ColumnType>, Self::Error> {
// println!(
// "[{}] Running query: \"{}\"",
// self.relative_path.display(),
// sql
// );
let mut conn = self.connection().await;
run_query(sql, &mut conn).await
}
Expand All @@ -223,13 +228,18 @@ impl sqllogictest::AsyncDB for ParadeDB {
}

async fn run_query(sql: impl Into<String> + Query, conn: &mut PgConnection) -> Result<DFOutput> {
let results: Vec<PgRow> = sql.fetch_dynamic(conn);
// let rows = normalize::convert_batches(results)?;
Ok(DBOutput::StatementComplete(0))

// if rows.is_empty() && types.is_empty() {
// Ok(DBOutput::StatementComplete(0))
// } else {
// Ok(DBOutput::Rows { types, rows })
// }
let results: Vec<PgRow> = sql.fetch_dynamic_result(conn)?;

let rows = convert_rows(&results);
let types = if rows.is_empty() {
vec![]
} else {
convert_types(results[0].columns())
};

if rows.is_empty() && types.is_empty() {
Ok(DBOutput::StatementComplete(0))
} else {
Ok(DBOutput::Rows { types, rows })
}
}
18 changes: 3 additions & 15 deletions tests/sqllogictests/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Copyright (c) 2023-2024 Retake, Inc.
//
// This file is part of ParadeDB - Postgres for Search and Analytics
Expand All @@ -25,12 +15,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

// TECH DEBT: This file is a copy of the `db.rs` file from https://github.com/paradedb/paradedb/blob/dev/shared/src/fixtures/db.rs
// We duplicated because the paradedb repo may use a different version of pgrx than pg_analytics, but eventually we should
// move this into a separate crate without any dependencies on pgrx.

use datafusion::arrow::error::ArrowError;
// use datafusion_common::DataFusionError;
use sqllogictest::TestError;
use sqlparser::parser::ParserError;
use thiserror::Error;
Expand All @@ -40,6 +25,9 @@ pub type Result<T, E = DFSqlLogicTestError> = std::result::Result<T, E>;
/// DataFusion sql-logicaltest error
#[derive(Debug, Error)]
pub enum DFSqlLogicTestError {
/// Error from sqlx
#[error("Postgres error(from sqlx crate): {0}")]
Sqlx(#[from] sqlx::Error),
/// Error from sqllogictest-rs
#[error("SqlLogicTest error(from sqllogictest-rs crate): {0}")]
SqlLogicTest(#[from] TestError),
Expand Down
2 changes: 2 additions & 0 deletions tests/sqllogictests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod arrow;
mod conversion;
pub mod engine;
mod error;
mod normalize;
mod output;
Loading

0 comments on commit 232badb

Please sign in to comment.