You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@seata.apache.org by "XiaoFeiASK (via GitHub)" <gi...@apache.org> on 2026/09/12 12:42:41 UTC

Re: [PR] fix: handle postgres placeholders in string literals [incubator-seata-go]

XiaoFeiASK commented on code in PR #1146:
URL: https://github.com/apache/incubator-seata-go/pull/1146#discussion_r3911138758


##########
pkg/datasource/sql/util/placeholders.go:
##########
@@ -108,3 +118,178 @@ func CompactPostgreSQLPlaceholders(query string, args []driver.NamedValue) (stri
 
 	return builder.String(), compactedArgs, nil
 }
+
+// StripPostgreSQLStringCharset removes MySQL charset introducers emitted by the
+// parser for string literals. PostgreSQL does not accept _UTF8MB4'...', and the
+// following placeholder compaction must still see the literal quotes.
+func StripPostgreSQLStringCharset(query string) string {
+	const utf8mb4 = "_UTF8MB4"
+	found := false
+	for i := 0; i+len(utf8mb4) < len(query); i++ {
+		if hasPostgreSQLUTF8MB4StringIntroducer(query, i) {
+			found = true
+			break
+		}
+	}
+	if !found {
+		return query
+	}
+
+	var builder strings.Builder
+	builder.Grow(len(query))
+
+	for i := 0; i < len(query); {
+		if next, ok := copyPostgreSQLNonCode(query, i, &builder); ok {
+			i = next
+			continue
+		}
+
+		if hasPostgreSQLUTF8MB4StringIntroducer(query, i) {
+			i += len(utf8mb4)
+			continue
+		}
+
+		builder.WriteByte(query[i])
+		i++
+	}
+
+	return builder.String()
+}
+
+func hasPostgreSQLUTF8MB4StringIntroducer(query string, start int) bool {
+	const utf8mb4 = "_UTF8MB4"
+	end := start + len(utf8mb4)
+	return end < len(query) &&
+		query[end] == '\'' &&
+		(start == 0 || !isPostgreSQLIdentifierPart(query[start-1])) &&
+		strings.EqualFold(query[start:end], utf8mb4)
+}
+
+// copyPostgreSQLNonCode copies a quoted string, quoted identifier, comment,
+// or dollar-quoted string starting at start. Placeholders inside these regions
+// are SQL text and must not be rewritten.
+func copyPostgreSQLNonCode(query string, start int, builder *strings.Builder) (int, bool) {
+	if start >= len(query) {
+		return start, false
+	}
+
+	var end int
+	switch query[start] {
+	case '\'':
+		end = scanPostgreSQLQuoted(query, start, '\'')
+	case '"':
+		end = scanPostgreSQLQuoted(query, start, '"')
+	case '-':
+		if start+1 >= len(query) || query[start+1] != '-' {
+			return start, false
+		}
+		end = start + 2
+		for end < len(query) && query[end] != '\n' && query[end] != '\r' {
+			end++
+		}
+	case '/':
+		if start+1 >= len(query) || query[start+1] != '*' {
+			return start, false
+		}
+		end = scanPostgreSQLBlockComment(query, start)
+	case '$':
+		delimiter, ok := postgreSQLDollarQuoteDelimiter(query, start)

Review Comment:
   PostgreSQL 未加引号的标识符允许包含 $,例如 user$tag$。当前未检查 start 前一个字符是否为标识符字符,会把其中的 $tag$ 误判为 dollar-quote;若找不到闭合 delimiter,将吞掉后续 SQL,导致后续 ?/$n 占位符无法改写。请增加 token boundary 判断,并补充该场景测试。



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@seata.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@seata.apache.org
For additional commands, e-mail: notifications-help@seata.apache.org