(
scx: &StatementContext,
mut stmt: CreateWebhookSourceStatement<Aug>,
)
| 558 | ); |
| 559 | |
| 560 | pub fn plan_create_webhook_source( |
| 561 | scx: &StatementContext, |
| 562 | mut stmt: CreateWebhookSourceStatement<Aug>, |
| 563 | ) -> Result<Plan, PlanError> { |
| 564 | if stmt.is_table { |
| 565 | scx.require_feature_flag(&ENABLE_CREATE_TABLE_FROM_SOURCE)?; |
| 566 | } |
| 567 | |
| 568 | // We will rewrite the cluster if one is not provided, so we must use the `in_cluster` value |
| 569 | // we plan to normalize when we canonicalize the create statement. |
| 570 | let in_cluster = source_sink_cluster_config(scx, &mut stmt.in_cluster)?; |
| 571 | let create_sql = |
| 572 | normalize::create_statement(scx, Statement::CreateWebhookSource(stmt.clone()))?; |
| 573 | |
| 574 | let CreateWebhookSourceStatement { |
| 575 | name, |
| 576 | if_not_exists, |
| 577 | body_format, |
| 578 | include_headers, |
| 579 | validate_using, |
| 580 | is_table, |
| 581 | // We resolved `in_cluster` above, so we want to ignore it here. |
| 582 | in_cluster: _, |
| 583 | } = stmt; |
| 584 | |
| 585 | let validate_using = validate_using |
| 586 | .map(|stmt| query::plan_webhook_validate_using(scx, stmt)) |
| 587 | .transpose()?; |
| 588 | if let Some(WebhookValidation { expression, .. }) = &validate_using { |
| 589 | // If the validation expression doesn't reference any part of the request, then we should |
| 590 | // return an error because it's almost definitely wrong. |
| 591 | if !expression.contains_column() { |
| 592 | return Err(PlanError::WebhookValidationDoesNotUseColumns); |
| 593 | } |
| 594 | // Validation expressions cannot contain unmaterializable functions, except `now()`. We |
| 595 | // allow calls to `now()` because some webhook providers recommend rejecting requests that |
| 596 | // are older than a certain threshold. |
| 597 | if expression.contains_unmaterializable_except(&[UnmaterializableFunc::CurrentTimestamp]) { |
| 598 | return Err(PlanError::WebhookValidationNonDeterministic); |
| 599 | } |
| 600 | } |
| 601 | |
| 602 | let body_format = match body_format { |
| 603 | Format::Bytes => WebhookBodyFormat::Bytes, |
| 604 | Format::Json { array } => WebhookBodyFormat::Json { array }, |
| 605 | Format::Text => WebhookBodyFormat::Text, |
| 606 | // TODO(parkmycar): Make an issue to support more types, or change this to NeverSupported. |
| 607 | ty => { |
| 608 | return Err(PlanError::Unsupported { |
| 609 | feature: format!("{ty} is not a valid BODY FORMAT for a WEBHOOK source"), |
| 610 | discussion_no: None, |
| 611 | }); |
| 612 | } |
| 613 | }; |
| 614 | |
| 615 | let mut column_ty = vec![ |
| 616 | // Always include the body of the request as the first column. |
| 617 | SqlColumnType { |
no test coverage detected