Skip to content

SQL queries are truncated when Chinese comments are present #4235

@aitsuki

Description

@aitsuki

Version

1.30.0

What happened?

When SQL files contain Chinese (or other multi-byte UTF-8) comments, sqlc incorrectly truncates the generated SQL query constants in the Go code. The truncation occurs at or near the position of the Chinese characters, resulting in incomplete SQL statements.

Reproduce

app_item.sql

-- name: CreateMissingAppItemsForAllApp :exec
-- 当新建MasterItem时,需要为所有App创建相应的AppItem
INSERT INTO app_items (app_id, master_item_id)
SELECT a.id, ? FROM apps a
WHERE NOT EXISTS (
    SELECT 1 FROM app_items ai 
    WHERE ai.app_id = a.id AND ai.master_item_id = ?
);

-- name: ResetAppItemStatusByMasterItem :exec
-- 当修改MasterItem后需要同步给所有AppItem
UPDATE app_items
SET status = 'pending',
    remark = '',
    last_synced_at = CURRENT_TIMESTAMP
WHERE master_item_id = ?;


-- name: CreateAppItemsForApp :exec
-- 当新建App时,需要为该APP创建所有AppItem
INSERT INTO app_items (app_id, master_item_id)
SELECT ?, id FROM master_items;

-- name: UpdateAppItem :exec
UPDATE app_items
SET status = ?,
    remark = ?,
    updated_at = CURRENT_TIMESTAMP
WHERE id = ?;

-- name: ListAppItemsByAppID :many
SELECT 
    ai.id,
    ai.app_id,
    ai.master_item_id,
    m.title,
    m.description,
    ai.status,
    ai.remark,
    ai.last_synced_at,
    ai.updated_at
FROM app_items ai
JOIN master_items m ON ai.master_item_id = m.id
WHERE ai.app_id = ?
ORDER BY ai.id;

-- name: GetAppItemByID :one
SELECT * FROM app_items
WHERE id = ?;

-- name: CountPendingByAppID :one
SELECT COUNT(*) as count
FROM app_items
WHERE app_id = ?
AND status = 'pending';

app_item.sql.go

// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.30.0
// source: app_item.sql

package database

import (
	"context"
	"time"
)

const createAppItemsForApp = `-- name: CreateAppItemsForApp :exec
ced_at = CURRENT_TIMESTAMP
WHERE master_item_id = ?;


`

// 当新建App时,需要为该APP创建所有AppItem
func (q *Queries) CreateAppItemsForApp(ctx context.Context, appID int64) error {
	_, err := q.db.ExecContext(ctx, createAppItemsForApp, appID)
	return err
}

const createMissingAppItemsForAllApp = `-- name: CreateMissingAppItemsForAllApp :exec
INSERT INTO app_items (app_id, master_item_id)
SELECT a.id, ? FROM apps a
WHERE NOT EXISTS (
    SELECT 1 FROM app_items ai 
    WHERE ai.app_id = a.
`

// 当新建MasterItem时,需要为所有App创建相应的AppItem
func (q *Queries) CreateMissingAppItemsForAllApp(ctx context.Context, masterItemID int64) error {
	_, err := q.db.ExecContext(ctx, createMissingAppItemsForAllApp, masterItemID)
	return err
}

const getAppItemByID = `-- name: GetAppItemByID :one
BY ai.id;

SELECT * FROM app_items
WHERE id = ?;

S
`

func (q *Queries) GetAppItemByID(ctx context.Context, appID int64) (int64, error) {
	row := q.db.QueryRowContext(ctx, getAppItemByID, appID)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const listAppItemsByAppID = `-- name: ListAppItemsByAppID :many
T status = ?,
    remark = ?,
    updated_at = CURRENT_TIMESTAMP
WHERE id = ?;

SELECT 
    ai.id,
    ai.app_id,
    ai.master_item_id,
    m.title,
    m.description,
    ai.status,
    ai.remark,
    ai.last_synced_at,
    ai.updated_at
FROM app_items ai
JOIN
`

type ListAppItemsByAppIDRow struct {
	ID           int64
	AppID        int64
	MasterItemID int64
	Title        string
	Description  string
	Status       string
	Remark       string
	LastSyncedAt time.Time
	UpdatedAt    time.Time
}

func (q *Queries) ListAppItemsByAppID(ctx context.Context, appID int64) ([]ListAppItemsByAppIDRow, error) {
	rows, err := q.db.QueryContext(ctx, listAppItemsByAppID, appID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListAppItemsByAppIDRow
	for rows.Next() {
		var i ListAppItemsByAppIDRow
		if err := rows.Scan(
			&i.ID,
			&i.AppID,
			&i.MasterItemID,
			&i.Title,
			&i.Description,
			&i.Status,
			&i.Remark,
			&i.LastSyncedAt,
			&i.UpdatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const resetAppItemStatusByMasterItem = `-- name: ResetAppItemStatusByMasterItem :exec
d AND ai.master_item_id = ?
);

UPDATE app_items
SET status = 'pending',
    remark = '',
    last_sy
`

// 当修改MasterItem后需要同步给所有AppItem
func (q *Queries) ResetAppItemStatusByMasterItem(ctx context.Context, masterItemID int64) error {
	_, err := q.db.ExecContext(ctx, resetAppItemStatusByMasterItem, masterItemID)
	return err
}

const updateAppItem = `-- name: UpdateAppItem :exec
INSERT INTO app_items (app_id, master_item_id)
SELECT ?, id FROM master_items;

UPDATE app_items
S
`

type UpdateAppItemParams struct {
	Status string
	Remark string
	ID     int64
}

func (q *Queries) UpdateAppItem(ctx context.Context, arg UpdateAppItemParams) error {
	_, err := q.db.ExecContext(ctx, updateAppItem, arg.Status, arg.Remark, arg.ID)
	return err
}

Note:Note: The content appears corrupted/mixed with other queries and incomplete.
Removing Chinese comments or using English comments will generate correct code.

Strangely, I did not reproduce this issue on another computer (using the same environment)

Relevant log output

Database schema

CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL UNIQUE,
    pass BLOB NOT NULL,
    admin BOOLEAN NOT NULL DEFAULT 0,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE master_items (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    description TEXT NOT NULL DEFAULT '',
    propose_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE apps (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL UNIQUE,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE app_items (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    app_id INTEGER NOT NULL,
    master_item_id INTEGER NOT NULL,
    status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'checked', 'ignored', 'publish')),
    publish_version TEXT NOT NULL DEFAULT '1.0.0',
    remark TEXT NOT NULL DEFAULT '',
    last_synced_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE,
    FOREIGN KEY (master_item_id) REFERENCES master_items(id) ON DELETE CASCADE,
    UNIQUE(app_id, master_item_id)
);
CREATE INDEX idx_app_items_app_id ON app_items(app_id);
CREATE INDEX idx_app_items_master_item_id ON app_items(master_item_id);
CREATE INDEX idx_app_items_status ON app_items(status);
CREATE INDEX idx_app_items_app_status ON app_items(app_id, status);

SQL queries

-- name: CreateMissingAppItemsForAllApp :exec
-- 当新建MasterItem时,需要为所有App创建相应的AppItem
INSERT INTO app_items (app_id, master_item_id)
SELECT a.id, ? FROM apps a
WHERE NOT EXISTS (
    SELECT 1 FROM app_items ai 
    WHERE ai.app_id = a.id AND ai.master_item_id = ?
);

-- name: ResetAppItemStatusByMasterItem :exec
-- 当修改MasterItem后需要同步给所有AppItem
UPDATE app_items
SET status = 'pending',
    remark = '',
    last_synced_at = CURRENT_TIMESTAMP
WHERE master_item_id = ?;


-- name: CreateAppItemsForApp :exec
-- 当新建App时,需要为该APP创建所有AppItem
INSERT INTO app_items (app_id, master_item_id)
SELECT ?, id FROM master_items;

-- name: UpdateAppItem :exec
UPDATE app_items
SET status = ?,
    remark = ?,
    updated_at = CURRENT_TIMESTAMP
WHERE id = ?;

-- name: ListAppItemsByAppID :many
SELECT 
    ai.id,
    ai.app_id,
    ai.master_item_id,
    m.title,
    m.description,
    ai.status,
    ai.remark,
    ai.last_synced_at,
    ai.updated_at
FROM app_items ai
JOIN master_items m ON ai.master_item_id = m.id
WHERE ai.app_id = ?
ORDER BY ai.id;

-- name: GetAppItemByID :one
SELECT * FROM app_items
WHERE id = ?;

-- name: CountPendingByAppID :one
SELECT COUNT(*) as count
FROM app_items
WHERE app_id = ?
AND status = 'pending';

Configuration

version: "2"
sql:
  - engine: "sqlite"
    queries: "queries"
    schema: "migrations"
    gen:
      go:
        package: "database"
        out: "database"

Playground URL

No response

What operating system are you using?

Windows

What database engines are you using?

SQLite

What type of code are you generating?

Go

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions