risingwave_frontend/handler/create_source/
additional_column.rs1use super::*;
16
17fn check_additional_column_compatibility(
19 column_def: &IncludeOptionItem,
20 format_encode: Option<&FormatEncodeOptions>,
21) -> Result<()> {
22 if column_def.inner_field.is_some()
24 && !column_def
25 .column_type
26 .real_value()
27 .eq_ignore_ascii_case("header")
28 {
29 return Err(RwError::from(ProtocolError(format!(
30 "Only header column can have inner field, but got {:?}",
31 column_def.column_type.real_value(),
32 ))));
33 }
34
35 if let Some(schema) = format_encode
37 && column_def
38 .column_type
39 .real_value()
40 .eq_ignore_ascii_case("payload")
41 && !matches!(schema.row_encode, Encode::Json)
42 {
43 return Err(RwError::from(ProtocolError(format!(
44 "INCLUDE payload is only allowed when using ENCODE JSON, but got ENCODE {:?}",
45 schema.row_encode
46 ))));
47 }
48 Ok(())
49}
50
51pub fn handle_addition_columns(
53 format_encode: Option<&FormatEncodeOptions>,
54 with_properties: &BTreeMap<String, String>,
55 mut additional_columns: IncludeOption,
56 columns: &mut Vec<ColumnCatalog>,
57 is_cdc_backfill_table: bool,
58) -> Result<()> {
59 let connector_name = with_properties.get_connector().unwrap(); while let Some(item) = additional_columns.pop() {
62 check_additional_column_compatibility(&item, format_encode)?;
63
64 let data_type = item
65 .header_inner_expect_type
66 .map(|dt| bind_data_type(&dt))
67 .transpose()?;
68 if let Some(dt) = &data_type
69 && !matches!(dt, DataType::Bytea | DataType::Varchar)
70 {
71 return Err(
72 ErrorCode::BindError(format!("invalid additional column data type: {dt}")).into(),
73 );
74 }
75 let col = build_additional_column_desc(
76 ColumnId::placeholder(),
77 connector_name.as_str(),
78 item.column_type.real_value().as_str(),
79 item.column_alias.map(|alias| alias.real_value()),
80 item.inner_field.as_deref(),
81 data_type.as_ref(),
82 true,
83 is_cdc_backfill_table,
84 )?;
85 columns.push(ColumnCatalog::visible(col));
86 }
87
88 Ok(())
89}
90
91pub fn check_and_add_timestamp_column(
93 with_properties: &WithOptions,
94 columns: &mut Vec<ColumnCatalog>,
95) {
96 if with_properties.is_kafka_connector() {
97 if columns.iter().any(|col| {
98 matches!(
99 col.column_desc.additional_column.column_type,
100 Some(AdditionalColumnType::Timestamp(_))
101 )
102 }) {
103 return;
105 }
106
107 let col = build_additional_column_desc(
109 ColumnId::placeholder(),
110 KAFKA_CONNECTOR,
111 "timestamp",
112 Some(KAFKA_TIMESTAMP_COLUMN_NAME.to_owned()),
113 None,
114 None,
115 true,
116 false,
117 )
118 .unwrap();
119 columns.push(ColumnCatalog::hidden(col));
120 }
121}