Skip to content

Commit d96477a

Browse files
committed
sql: allow aliasing column names
This will enable some transformations that will in turn enable record types. It also unlocks a slew of CockroachDB sqllogictests, some of which are enabled here. Fix #3112.
1 parent ba0e600 commit d96477a

File tree

7 files changed

+264
-241
lines changed

7 files changed

+264
-241
lines changed

ci/test/slt-fast.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ tests=(
126126
# test/sqllogictest/cockroach/select_index_span_ranges.slt
127127
# test/sqllogictest/cockroach/select_index.slt
128128
test/sqllogictest/cockroach/select_search_path.slt
129-
# test/sqllogictest/cockroach/select_table_alias.slt
129+
test/sqllogictest/cockroach/select_table_alias.slt
130130
# test/sqllogictest/cockroach/select.slt
131131
test/sqllogictest/cockroach/shift.slt
132132
# test/sqllogictest/cockroach/sqlsmith.slt
@@ -148,7 +148,7 @@ tests=(
148148
test/sqllogictest/cockroach/update.slt
149149
test/sqllogictest/cockroach/upsert.slt
150150
test/sqllogictest/cockroach/uuid.slt
151-
# test/sqllogictest/cockroach/values.slt
151+
test/sqllogictest/cockroach/values.slt
152152
# test/sqllogictest/cockroach/views.slt
153153
# test/sqllogictest/cockroach/where.slt
154154
test/sqllogictest/cockroach/window.slt

src/sql/src/plan/func.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use failure::bail;
1818
use lazy_static::lazy_static;
1919

2020
use ore::collections::CollectionExt;
21-
use repr::{ColumnType, Datum, ScalarType};
21+
use repr::{ColumnName, ColumnType, Datum, ScalarType};
2222
use sql_parser::ast::{BinaryOperator, Expr, UnaryOperator};
2323

2424
use super::cast::{self, rescale_decimal, CastTo};
@@ -1297,7 +1297,7 @@ pub fn plan_unary_op<'a>(
12971297
pub struct TableFuncPlan {
12981298
pub func: TableFunc,
12991299
pub exprs: Vec<ScalarExpr>,
1300-
pub column_names: Vec<String>,
1300+
pub column_names: Vec<Option<ColumnName>>,
13011301
}
13021302

13031303
lazy_static! {
@@ -1317,7 +1317,7 @@ lazy_static! {
13171317
Ok(TableFuncPlan {
13181318
func: TableFunc::CsvExtract(ncols),
13191319
exprs: vec![input],
1320-
column_names: (1..=ncols).map(|i| format!("column{}", i)).collect(),
1320+
column_names: (1..=ncols).map(|i| Some(format!("column{}", i).into())).collect(),
13211321
})
13221322
})
13231323
},
@@ -1330,7 +1330,7 @@ lazy_static! {
13301330
Ok(TableFuncPlan {
13311331
func: TableFunc::JsonbArrayElements { stringify: false },
13321332
exprs: vec![jsonb],
1333-
column_names: vec!["value".into()],
1333+
column_names: vec![Some("value".into())],
13341334
})
13351335
})
13361336
},
@@ -1339,7 +1339,7 @@ lazy_static! {
13391339
Ok(TableFuncPlan {
13401340
func: TableFunc::JsonbArrayElements { stringify: true },
13411341
exprs: vec![jsonb],
1342-
column_names: vec!["value".into()],
1342+
column_names: vec![Some("value".into())],
13431343
})
13441344
})
13451345
},
@@ -1348,7 +1348,7 @@ lazy_static! {
13481348
Ok(TableFuncPlan {
13491349
func: TableFunc::JsonbEach { stringify: false },
13501350
exprs: vec![jsonb],
1351-
column_names: vec!["key".into(), "value".into()],
1351+
column_names: vec![Some("key".into()), Some("value".into())],
13521352
})
13531353
})
13541354
},
@@ -1357,7 +1357,7 @@ lazy_static! {
13571357
Ok(TableFuncPlan {
13581358
func: TableFunc::JsonbEach { stringify: true },
13591359
exprs: vec![jsonb],
1360-
column_names: vec!["key".into(), "value".into()],
1360+
column_names: vec![Some("key".into()), Some("value".into())],
13611361
})
13621362
})
13631363
},
@@ -1366,7 +1366,7 @@ lazy_static! {
13661366
Ok(TableFuncPlan {
13671367
func: TableFunc::JsonbObjectKeys,
13681368
exprs: vec![jsonb],
1369-
column_names: vec!["jsonb_object_keys".into()],
1369+
column_names: vec![Some("jsonb_object_keys".into())],
13701370
})
13711371
})
13721372
},
@@ -1378,7 +1378,10 @@ lazy_static! {
13781378
};
13791379
let column_names = regex
13801380
.capture_groups_iter()
1381-
.map(|cg| cg.name.clone().unwrap_or_else(|| format!("column{}", cg.index)))
1381+
.map(|cg| {
1382+
let name = cg.name.clone().unwrap_or_else(|| format!("column{}", cg.index));
1383+
Some(name.into())
1384+
})
13821385
.collect();
13831386
Ok(TableFuncPlan {
13841387
func: TableFunc::RegexpExtract(regex),
@@ -1396,7 +1399,7 @@ fn plan_generate_series(ty: ScalarType) -> Operation<TableFuncPlan> {
13961399
Ok(TableFuncPlan {
13971400
func: TableFunc::GenerateSeries(ty.clone()),
13981401
exprs,
1399-
column_names: vec!["generate_series".into()],
1402+
column_names: vec![Some("generate_series".into())],
14001403
})
14011404
})
14021405
}

src/sql/src/plan/query.rs

Lines changed: 57 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -708,18 +708,6 @@ fn plan_table_factor<'a>(
708708
if !with_hints.is_empty() {
709709
unsupported!("WITH hints");
710710
}
711-
let alias = if let Some(TableAlias { name, columns }) = alias {
712-
if !columns.is_empty() {
713-
unsupported!(3112, "aliasing columns");
714-
}
715-
PartialName {
716-
database: None,
717-
schema: None,
718-
item: normalize::ident(name.clone()),
719-
}
720-
} else {
721-
normalize::object_name(name.clone())?
722-
};
723711
if let Some(args) = args {
724712
let ecx = &ExprContext {
725713
qcx,
@@ -729,19 +717,16 @@ fn plan_table_factor<'a>(
729717
allow_aggregates: false,
730718
allow_subqueries: true,
731719
};
732-
plan_table_function(ecx, left, &name, Some(alias), args)
720+
plan_table_function(ecx, left, &name, alias.as_ref(), args)
733721
} else {
734722
let name = qcx.scx.resolve_item(name.clone())?;
735723
let item = qcx.scx.catalog.get_item(&name);
736724
let expr = RelationExpr::Get {
737725
id: Id::Global(item.id()),
738726
typ: item.desc()?.typ().clone(),
739727
};
740-
let scope = Scope::from_source(
741-
Some(alias),
742-
item.desc()?.iter_names(),
743-
Some(qcx.outer_scope.clone()),
744-
);
728+
let column_names = item.desc()?.iter_names().map(|n| n.cloned()).collect();
729+
let scope = plan_table_alias(qcx, alias.as_ref(), Some(name.into()), column_names)?;
745730
plan_join_operator(qcx, &join_operator, left, left_scope, expr, scope)
746731
}
747732
}
@@ -754,20 +739,9 @@ fn plan_table_factor<'a>(
754739
unsupported!(3111, "LATERAL derived tables");
755740
}
756741
let (expr, scope) = plan_subquery(&qcx, &subquery)?;
757-
let alias = if let Some(TableAlias { name, columns }) = alias {
758-
if !columns.is_empty() {
759-
unsupported!(3112, "aliasing columns");
760-
}
761-
Some(PartialName {
762-
database: None,
763-
schema: None,
764-
item: normalize::ident(name.clone()),
765-
})
766-
} else {
767-
None
768-
};
769-
let scope =
770-
Scope::from_source(alias, scope.column_names(), Some(qcx.outer_scope.clone()));
742+
let table_name = None;
743+
let column_names = scope.column_names().map(|n| n.cloned()).collect();
744+
let scope = plan_table_alias(qcx, alias.as_ref(), table_name, column_names)?;
771745
plan_join_operator(qcx, &join_operator, left, left_scope, expr, scope)
772746
}
773747
TableFactor::NestedJoin(table_with_joins) => {
@@ -780,30 +754,71 @@ fn plan_table_function(
780754
ecx: &ExprContext,
781755
left: RelationExpr,
782756
name: &ObjectName,
783-
alias: Option<PartialName>,
757+
alias: Option<&TableAlias>,
784758
args: &FunctionArgs,
785759
) -> Result<(RelationExpr, Scope), failure::Error> {
786-
let ident = &*normalize::function_name(name.clone())?;
760+
let ident = normalize::function_name(name.clone())?;
787761
let args = match args {
788762
FunctionArgs::Star => bail!("{} does not accept * as an argument", ident),
789763
FunctionArgs::Args(args) => args,
790764
};
791-
let tf = func::select_table_func(ecx, ident, args)?;
765+
let tf = func::select_table_func(ecx, &*ident, args)?;
792766
let call = RelationExpr::FlatMap {
793767
input: Box::new(left),
794768
func: tf.func,
795769
exprs: tf.exprs,
796770
};
797-
let scope = Scope::from_source(
798-
alias,
799-
tf.column_names
800-
.iter()
801-
.map(|name| Some(ColumnName::from(&**name))),
802-
Some(ecx.qcx.outer_scope.clone()),
803-
);
771+
let name = PartialName {
772+
database: None,
773+
schema: None,
774+
item: ident,
775+
};
776+
let scope = plan_table_alias(ecx.qcx, alias, Some(name), tf.column_names)?;
804777
Ok((call, ecx.scope.clone().product(scope)))
805778
}
806779

780+
fn plan_table_alias(
781+
qcx: &QueryContext,
782+
alias: Option<&TableAlias>,
783+
inherent_table_name: Option<PartialName>,
784+
inherent_column_names: Vec<Option<ColumnName>>,
785+
) -> Result<Scope, failure::Error> {
786+
let table_name = match alias {
787+
None => inherent_table_name,
788+
Some(TableAlias { name, .. }) => Some(PartialName {
789+
database: None,
790+
schema: None,
791+
item: normalize::ident(name.to_owned()),
792+
}),
793+
};
794+
let column_names = match alias {
795+
None => inherent_column_names,
796+
Some(TableAlias { columns, .. }) if columns.is_empty() => inherent_column_names,
797+
Some(TableAlias { columns, .. }) if columns.len() > inherent_column_names.len() => {
798+
bail!(
799+
"{} has {} columns available but {} columns specified",
800+
table_name
801+
.map(|n| n.to_string())
802+
.as_deref()
803+
.unwrap_or("subquery"),
804+
inherent_column_names.len(),
805+
columns.len()
806+
);
807+
}
808+
Some(TableAlias { columns, .. }) => columns
809+
.iter()
810+
.cloned()
811+
.map(|n| Some(normalize::column_name(n)))
812+
.chain(inherent_column_names.into_iter().skip(columns.len()))
813+
.collect(),
814+
};
815+
Ok(Scope::from_source(
816+
table_name,
817+
column_names,
818+
Some(qcx.outer_scope.clone()),
819+
))
820+
}
821+
807822
fn plan_select_item<'a>(
808823
ecx: &ExprContext,
809824
s: &'a SelectItem,

0 commit comments

Comments
 (0)