Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 81 additions & 5 deletions spanner/spansql/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,88 @@ func (cp CreateProtoBundle) SQL() string {
}

func (cv CreateView) SQL() string {
str := "CREATE"
var sb strings.Builder
sb.WriteString("CREATE")
if cv.OrReplace {
str += " OR REPLACE"
sb.WriteString(" OR REPLACE")
}
sb.WriteString(" VIEW ")
sb.WriteString(cv.Name.SQL())
sb.WriteString(" SQL SECURITY ")
sb.WriteString(cv.SecurityType.SQL())
sb.WriteString(" AS ")
writeFormattedQuery(&sb, &cv.Query)
return sb.String()
}

func writeFormattedQuery(sb *strings.Builder, q *Query) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This is a great helper function for formatting queries! Once the missing DISTINCT and HAVING clauses are added, you could consider using this function to implement Query.SQL() to improve its formatting and address the // TODO: improve this. comment. This would make the SQL output for standalone queries consistent with the formatting inside CREATE VIEW.

It would look something like this:

func (q Query) SQL() string {
	var sb strings.Builder
	writeFormattedQuery(&sb, &q)
	return sb.String()
}

Note that this would change the output for existing query tests, so they would need to be updated.

sb.WriteString("SELECT\n")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The new writeFormattedQuery function doesn't handle SELECT DISTINCT. The q.Select.Distinct field is ignored, which will lead to incorrect SQL generation for views that use DISTINCT. This should be added after the SELECT keyword.

sb.WriteString("SELECT")
	if q.Select.Distinct {
		sb.WriteString(" DISTINCT")
	}
	sb.WriteString("\n")


// SELECT list with aliases
for i, expr := range q.Select.List {
sb.WriteString("\t")
sb.WriteString(expr.SQL())
// Add alias if available (check bounds safely)
if len(q.Select.ListAliases) > i && q.Select.ListAliases[i] != "" {
sb.WriteString(" AS ")
sb.WriteString(q.Select.ListAliases[i].SQL())
}
// Add comma and newline, except after last item
if i < len(q.Select.List)-1 {
sb.WriteString(",\n")
} else {
sb.WriteString("\n")
}
}

// FROM clause
if len(q.Select.From) > 0 {
sb.WriteString("FROM ")
for i, f := range q.Select.From {
if i > 0 {
sb.WriteString(", ")
}
sb.WriteString(f.SQL())
}
}

// WHERE clause
if q.Select.Where != nil {
sb.WriteString("\nWHERE ")
sb.WriteString(q.Select.Where.SQL())
}

// GROUP BY clause
if len(q.Select.GroupBy) > 0 {
sb.WriteString("\nGROUP BY ")
for i, gb := range q.Select.GroupBy {
if i > 0 {
sb.WriteString(", ")
}
sb.WriteString(gb.SQL())
}
}

// ORDER BY clause
if len(q.Order) > 0 {
sb.WriteString("\nORDER BY ")
for i, o := range q.Order {
if i > 0 {
sb.WriteString(", ")
}
sb.WriteString(o.SQL())
}
}
Comment thread
anicoll marked this conversation as resolved.
Outdated

// LIMIT/OFFSET clauses
if q.Limit != nil {
sb.WriteString("\nLIMIT ")
sb.WriteString(q.Limit.SQL())
if q.Offset != nil {
sb.WriteString(" OFFSET ")
sb.WriteString(q.Offset.SQL())
}
}
str += " VIEW " + cv.Name.SQL() + " SQL SECURITY " + cv.SecurityType.SQL() + " AS " + cv.Query.SQL()
return str
}

func (st SecurityType) SQL() string {
Expand Down Expand Up @@ -918,7 +994,7 @@ func (sft SelectFromTable) SQL() string {

func (sfj SelectFromJoin) SQL() string {
// TODO: The grammar permits arbitrary nesting. Does this need to add parens?
str := sfj.LHS.SQL() + " " + joinTypes[sfj.Type] + " JOIN "
str := sfj.LHS.SQL() + "\n" + joinTypes[sfj.Type] + " JOIN "

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While adding the newline here improves readability, this function and the lines that follow still use string concatenation (+ and +=). For consistency with the other changes in this PR (like in CreateView.SQL) that adopt strings.Builder, it would be beneficial to refactor this entire function to use strings.Builder as well. This would improve performance and maintainability.

// TODO: hints go here
str += sfj.RHS.SQL()
if sfj.On != nil {
Expand Down
Loading
Loading