use crate::ast::Expr;
use crate::catalog::Catalog;
use crate::error::DbError;
use crate::storage::Storage;
use crate::types::Value;
use super::common::eval_expr_to_value;
use crate::executor::clock::Clock;
use crate::executor::context::ExecutionContext;
use crate::executor::database_catalog::{
current_database_id, current_database_name, database_id_for_name, database_name_for_id,
recovery_model_for_name,
};
use crate::executor::model::ContextTable;
pub(crate) fn eval_databasepropertyex(
args: &[Expr],
row: &[ContextTable],
ctx: &mut ExecutionContext,
catalog: &dyn Catalog,
storage: &dyn Storage,
clock: &dyn Clock,
) -> Result<Value, DbError> {
if args.len() != 2 {
return Err(DbError::Execution(
"DATABASEPROPERTYEX expects 2 arguments".into(),
));
}
let db_val = eval_expr_to_value(&args[0], row, ctx, catalog, storage, clock)?;
let prop_val = eval_expr_to_value(&args[1], row, ctx, catalog, storage, clock)?;
if db_val.is_null() || prop_val.is_null() {
return Ok(Value::Null);
}
let db_name = match db_val {
Value::Int(v) => database_name_for_id(v).unwrap_or("").to_string(),
Value::BigInt(v) => database_name_for_id(v as i32).unwrap_or("").to_string(),
Value::SmallInt(v) => database_name_for_id(v as i32).unwrap_or("").to_string(),
Value::TinyInt(v) => database_name_for_id(v as i32).unwrap_or("").to_string(),
_ => db_val.to_string_value(),
};
let is_known_db = database_id_for_name(&db_name).is_some();
let active_db = current_database_name(ctx).to_string();
if !is_known_db && !active_db.eq_ignore_ascii_case(&db_name) {
return Ok(Value::Null);
}
let prop = prop_val.to_string_value().to_ascii_uppercase();
Ok(match prop.as_str() {
"COLLATION" => Value::NVarChar("SQL_Latin1_General_CP1_CI_AS".to_string()),
"STATUS" => Value::NVarChar("ONLINE".to_string()),
"UPDATEABILITY" => Value::NVarChar("READ_WRITE".to_string()),
"USERACCESS" => Value::NVarChar("MULTI_USER".to_string()),
"ISREADONLY" => Value::Int(0),
"ISANSINULLDEFAULT" | "ISANSI_NULL_DEFAULT" => {
Value::Int(if ctx.metadata.ansi_nulls { 1 } else { 0 })
}
"COMPATIBILITYLEVEL" => Value::Int(160),
"RECOVERY" | "RECOVERYMODEL" => Value::NVarChar(
recovery_model_for_name(&db_name)
.unwrap_or("FULL")
.to_string(),
),
"ISAUTOSHRINK" | "ISAUTO_SHRINK_ON" => Value::Int(0),
"ISAUTOCLOSE" | "ISAUTO_CLOSE_ON" => Value::Int(0),
"ISFULLTEXTENABLED" => Value::Int(0),
"ISBROKERPRIORITYHONORED" => Value::Int(0),
"ISBROKERENABLED" | "SERVICEBROKERENABLED" => Value::Int(0),
"ISARITHMETICABORT" | "ISARITHMETIC_ABORT" => Value::Int(0),
"ISCONCATNULLYIELDSNULL" | "ISCONCAT_NULL_YIELDS_NULL" => Value::Int(1),
"ISNUMERICROUNDABORT" | "ISNUMERIC_ROUNDABORT" => Value::Int(0),
"ISQUOTEDIDENTIFIER" | "ISQUOTED_IDENTIFIER" => Value::Int(1),
"ISRECURSIVETRIGENABLED" | "ISRECURSIVE_TRIGGERS_ENABLED" => Value::Int(0),
"ISDATEPRIORITYYMD" | "ISDATE_CORRELATION_OPTIMIZATION" => Value::Int(0),
"ISPARAMETERIZATIONFORCED" | "ISPARAMETERIZATION_FORCED" => Value::Int(0),
"ISSUPPLEMENTALLOGGINGENABLED" | "ISSUPPLEMENTAL_LOGGING" => Value::Int(0),
"ISTRANSFORMNOISEWORDSENABLED" | "ISTRANSFORM_NOISE_WORDS" => Value::Int(0),
"ISTRUSTWORTHY" | "ISTRUSTWORTHY_ON" => Value::Int(0),
"ISCURSORDEFAULT" | "ISCURSORCLOSE_ON_COMMIT" => Value::Int(0),
"ISINSTANDBY" => Value::Int(0),
"ISAUTOCREATESTATISTICS" | "ISAUTOCREATESTATISTICS_ON" => Value::Int(1),
"ISAUTOUPDATESTATISTICS" | "ISAUTOUPDATESTATISTICS_ON" => Value::Int(1),
"ISAUTOUPDATESTATISTICSASYNC" | "ISAUTOUPDATESTATISTICSASYNC_ON" => Value::Int(0),
"ISENCRYPTED" | "ISENCRYPTION_ON" => Value::Int(0),
"ISPUBLISHED" | "ISSUBSCRIBED" | "ISMERGEPUBLISHED" | "ISDISTRIBUTOR" => Value::Int(0),
"VERSION" => Value::Int(957),
_ => Value::Null,
})
}
pub(crate) fn eval_original_db_name(
args: &[Expr],
ctx: &ExecutionContext,
) -> Result<Value, DbError> {
if !args.is_empty() {
return Err(DbError::Execution(
"ORIGINAL_DB_NAME expects no arguments".into(),
));
}
Ok(Value::NVarChar(ctx.metadata.original_database.clone()))
}
pub(crate) fn eval_db_name(args: &[Expr], ctx: &ExecutionContext) -> Result<Value, DbError> {
if args.len() > 1 {
return Err(DbError::Execution(
"DB_NAME expects 0 or 1 arguments".into(),
));
}
if let Some(arg) = args.first() {
let name = match arg {
Expr::Integer(i) => database_name_for_id(*i as i32).unwrap_or("").to_string(),
Expr::String(s) | Expr::UnicodeString(s) if database_id_for_name(s).is_some() => {
s.clone()
}
_ => return Ok(Value::Null),
};
if name.is_empty() {
return Ok(Value::Null);
}
return Ok(Value::NVarChar(name));
}
Ok(Value::NVarChar(current_database_name(ctx).to_string()))
}
pub(crate) fn eval_db_id(args: &[Expr], ctx: &ExecutionContext) -> Result<Value, DbError> {
if args.len() > 1 {
return Err(DbError::Execution("DB_ID expects 0 or 1 arguments".into()));
}
if let Some(arg) = args.first() {
return Ok(match arg {
Expr::Integer(i) if database_name_for_id(*i as i32).is_some() => Value::Int(*i as i32),
Expr::String(s) | Expr::UnicodeString(s) => database_id_for_name(s)
.map(Value::Int)
.unwrap_or(Value::Null),
_ => Value::Null,
});
}
Ok(Value::Int(current_database_id(ctx)))
}