hashicorp/terraform-provider-aws

[Enhancement]: aws_athena_prepared_statement: Allow multiline (EOT) query strings to preserve comments and line breaks without update-in-place

Open

#41,469 opened on Feb 19, 2025

 (6 comments) (0 reactions) (0 assignees)Go (10,312 forks)github user discovery
enhancementgood first issueservice/athena

Repository metrics

Stars
 (11,045 stars)
PR merge metrics
 (Avg merge 19d 21h) (251 merged PRs in 30d)

Description

Description

Hello,

Bit of a noob here, I'd appreciate any feedback on this request, maybe there's something I'm missing. I am using the Terraform aws_athena_prepared_statement resource and would like to know if it's intended behavior for Terraform to attempt to update the query statement attribute of my resource in-place every time I run terraform apply given that the query_string attribute is a multiline EOT string literal.

Steps to reproduce:

Here's my example setup:

terraform {
  required_providers {
    random = {
      source = "hashicorp/random"
      version = "3.5.1"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "test" {
  bucket        = "the-best-bucket-of-all-time"
  force_destroy = true
}

resource "aws_athena_workgroup" "test" {
  name = "tf-test"
}

resource "aws_athena_database" "test" {
  name   = "example"
  bucket = aws_s3_bucket.test.bucket
}

resource "aws_athena_prepared_statement" "test" {
  name            = "tf_test"
  query_statement = <<EOT
    SELECT
      -- The best comment of all time
      *
    FROM ${aws_athena_database.test.name} WHERE x = ?
  EOT
  workgroup       = aws_athena_workgroup.test.name
}

Each time I run the terraform plan command, I will see the below plan even without any changes to my statement:

aws_athena_workgroup.test: Refreshing state... [id=tf-test]
aws_s3_bucket.test: Refreshing state... [id=the-best-bucket-of-all-time]
aws_athena_database.test: Refreshing state... [id=example]
aws_athena_prepared_statement.test: Refreshing state... [id=tf-test/tf_test]

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_athena_prepared_statement.test will be updated in-place
  ~ resource "aws_athena_prepared_statement" "test" {
        id              = "tf-test/tf_test"
        name            = "tf_test"
      ~ query_statement = <<-EOT
            SELECT
                -- The best comment of all time
                  *
                FROM example WHERE x = ?
        EOT
        # (2 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly
these actions if you run "terraform apply" now.

I know that I could write code to clean the input statement, such that the user can still write multiline SQL, but writing complex regexs to replace single or multiline comments is kind of challenging.

My guess would be that when Terraform checks the state of the prepared statement (is that this?) it is doing something like: aws athena get-prepared-statement --statement-name tf_test --work-group tf-test, which evaluates to: SELECT\n -- The best comment of all time\n *\n FROM example WHERE x = ?\n /* Another \n multi-line \n comment */, evidently I suppose this is different than what input.QueryStatement is equal to.

I tried to set the query statement to be exactly like what the AWS api is giving by doing:

locals {
  sql = <<EOT
    SELECT
      -- The best comment of all time
      *
    FROM ${aws_athena_database.test.name} WHERE x = ?
    /* Another 
       multi-line 
       comment */
  EOT
}

terraform {
  required_providers {
    random = {
      source = "hashicorp/random"
      version = "3.5.1"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "test" {
  bucket        = "the-best-bucket-of-all-time"
  force_destroy = true
}

resource "aws_athena_workgroup" "test" {
  name = "tf-test"
}

resource "aws_athena_database" "test" {
  name   = "example"
  bucket = aws_s3_bucket.test.bucket
}

resource "aws_athena_prepared_statement" "test" {
  name            = "tf_test"
  query_statement = jsonencode(trimspace(local.sql))
  workgroup       = aws_athena_workgroup.test.name
}

but then this gives me an operation error, like as if the input is malformed. In addition, the plan I see is not as readable as if the SQL was split across multiple lines.

Please let me know your thoughts or feedback, thank you!

Affected Resource(s) and/or Data Source(s)

  • aws_athena_prepared_statement

Potential Terraform Configuration

terraform {
  required_providers {
    random = {
      source = "hashicorp/random"
      version = "3.5.1"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "test" {
  bucket        = "the-best-bucket-of-all-time"
  force_destroy = true
}

resource "aws_athena_workgroup" "test" {
  name = "tf-test"
}

resource "aws_athena_database" "test" {
  name   = "example"
  bucket = aws_s3_bucket.test.bucket
}

resource "aws_athena_prepared_statement" "test" {
  name            = "tf_test"
  query_statement = <<EOT
    SELECT
    -- The best comment of all time
      *
    FROM ${aws_athena_database.test.name} WHERE x = ?
  EOT
  workgroup       = aws_athena_workgroup.test.name
}

References

Would you like to implement a fix?

No

Contributor guide