diff --git a/go/vehicle-gateway/internal/history/query.go b/go/vehicle-gateway/internal/history/query.go index 93a28877..0b659e0c 100644 --- a/go/vehicle-gateway/internal/history/query.go +++ b/go/vehicle-gateway/internal/history/query.go @@ -137,41 +137,38 @@ func normalizeRawFrameQuery(query RawFrameQuery) RawFrameQuery { func buildRawFrameSQL(table string, query RawFrameQuery) (string, []any) { var where []string - var args []any - add := func(clause string, value any) { + add := func(clause string) { where = append(where, clause) - args = append(args, value) } if query.Protocol != "" { - add("protocol = ?", query.Protocol) + add("protocol = '" + quote(query.Protocol) + "'") } if query.VIN != "" { - add("vin = ?", query.VIN) + add("vin = '" + quote(query.VIN) + "'") } if query.Phone != "" { - add("phone = ?", query.Phone) + add("phone = '" + quote(query.Phone) + "'") } if query.DeviceID != "" { - add("device_id = ?", query.DeviceID) + add("device_id = '" + quote(query.DeviceID) + "'") } if query.MessageID != "" { if parsed, ok := parseMessageID(query.MessageID); ok { - add("message_id = ?", parsed) + add("message_id = " + strconv.FormatInt(parsed, 10)) } } if query.DateFrom != "" { - add("ts >= ?", query.DateFrom) + add("ts >= '" + quote(query.DateFrom) + "'") } if query.DateTo != "" { - add("ts <= ?", query.DateTo) + add("ts <= '" + quote(query.DateTo) + "'") } sqlText := `SELECT ts, frame_id, event_id, message_id, event_time, received_at, raw_size_bytes, raw_hex, raw_text, parsed_json, fields_json, parse_status, parse_error, source_endpoint, protocol, vehicle_key, vin, phone, device_id FROM ` + table if len(where) > 0 { sqlText += " WHERE " + strings.Join(where, " AND ") } - sqlText += " ORDER BY ts DESC LIMIT ? OFFSET ?" - args = append(args, query.Limit, query.Offset) - return sqlText, args + sqlText += " ORDER BY ts DESC LIMIT " + strconv.Itoa(query.Limit) + " OFFSET " + strconv.Itoa(query.Offset) + return sqlText, nil } type RawFrameHandler struct { diff --git a/go/vehicle-gateway/internal/history/query_test.go b/go/vehicle-gateway/internal/history/query_test.go index 15c6c994..0a4c990c 100644 --- a/go/vehicle-gateway/internal/history/query_test.go +++ b/go/vehicle-gateway/internal/history/query_test.go @@ -19,7 +19,6 @@ func TestRawFrameRepositoryQueriesRawFramesWithFilters(t *testing.T) { } defer db.Close() mock.ExpectQuery("SELECT ts, frame_id, event_id, message_id, event_time, received_at, raw_size_bytes, raw_hex, raw_text, parsed_json, fields_json, parse_status, parse_error, source_endpoint, protocol, vehicle_key, vin, phone, device_id FROM lingniu_vehicle_ts.raw_frames"). - WithArgs("JT808", "LKLG7C4E3NA774736", "2026-07-01 00:00:00", "2026-07-01 23:59:59", 20, 0). WillReturnRows(sqlmock.NewRows([]string{ "ts", "frame_id", "event_id", "message_id", "event_time", "received_at", "raw_size_bytes", "raw_hex", "raw_text", "parsed_json", "fields_json", "parse_status", "parse_error", "source_endpoint", @@ -65,7 +64,6 @@ func TestRawFrameHandlerReturnsRawFrames(t *testing.T) { } defer db.Close() mock.ExpectQuery("SELECT ts, frame_id, event_id, message_id, event_time, received_at, raw_size_bytes, raw_hex, raw_text, parsed_json, fields_json, parse_status, parse_error, source_endpoint, protocol, vehicle_key, vin, phone, device_id FROM lingniu_vehicle_ts.raw_frames"). - WithArgs("GB32960", "LB9A32A21R0LS1707", 5, 0). WillReturnRows(sqlmock.NewRows([]string{ "ts", "frame_id", "event_id", "message_id", "event_time", "received_at", "raw_size_bytes", "raw_hex", "raw_text", "parsed_json", "fields_json", "parse_status", "parse_error", "source_endpoint", @@ -120,3 +118,28 @@ func TestParseMessageIDSupportsDecimalAndHex(t *testing.T) { } } } + +func TestBuildRawFrameSQLUsesLiteralsForTDengine(t *testing.T) { + sqlText, args := buildRawFrameSQL("lingniu_vehicle_ts.raw_frames", RawFrameQuery{ + Protocol: "JT808", + VIN: "VIN'1", + MessageID: "0x0200", + DateFrom: "2026-07-01 00:00:00", + DateTo: "2026-07-01 23:59:59", + Limit: 20, + Offset: 5, + }) + if len(args) != 0 { + t.Fatalf("expected no query args for TDengine, got %#v", args) + } + for _, want := range []string{ + "protocol = 'JT808'", + "vin = 'VIN''1'", + "message_id = 512", + "LIMIT 20 OFFSET 5", + } { + if !strings.Contains(sqlText, want) { + t.Fatalf("sql missing %s: %s", want, sqlText) + } + } +}