Skip to content

Occasional syntax errors from well formed search queries #233

Closed
@mirober

Description

@mirober

This is quite a tricky one to reproduce. We are running pgstac in production and very occasionally get pq: syntax error at end of input errors from pgstac search queries. The queries look well formed when we log them.

Looking at the database logs I can see:

STATEMENT:  SELECT search($1::jsonb);
ERROR:  syntax error at end of input at character 49
QUERY:  EXPLAIN (format json) SELECT 1 FROM items WHERE
CONTEXT:  PL/pgSQL function where_stats(text,boolean,jsonb) line 103 at EXECUTE
PL/pgSQL function search(jsonb) line 31 at assignment

We are running version 0.8.1, so that line is here - https://github.com/stac-utils/pgstac/blob/v0.8.1/src/pgstac/sql/004_search.sql#L497

I stared at this for a while and couldn't figure out how that where clause could be an empty string, so I started trying to reproduce it locally.

I ended up running 0.8.2 in a container with:

docker run \
-e POSTGRES_DB=stac \
-e POSTGRES_PASSWORD=admin \
-e POSTGRES_USER=admin \
-e PGUSER=admin \
-e PGPASSWORD=admin \
-e PGDATABASE=stac \
-p 5432:5432 \
ghcr.io/stac-utils/pgstac:v0.8.2 \
postgres -c 'log_statement=all'

Then:

  1. Install Golang if you don't have it already
  2. Create a new directory
  3. Drop the following file into main.go
package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"log"
	"sync"

	_ "github.com/lib/pq"
)

const (
	host     = "localhost"
	port     = 5432
	user     = "admin"
	password = "admin"
	dbname   = "stac"
)

// docker run -e POSTGRES_DB=stac -e POSTGRES_PASSWORD=admin -e POSTGRES_USER=admin -e PGUSER=admin -e PGPASSWORD=admin -e PGDATABASE=stac -p 5432:5432 ghcr.io/stac-utils/pgstac:v0.8.2 postgres -c 'log_statement=all'

func main() {
	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, port, user, password, dbname)

	db, err := sql.Open("postgres", psqlInfo)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	log.Println("Successfully connected!")

	query := `SELECT search('{"limit": 1}'::jsonb);`
	log.Printf("Search query: %#v", query)

	wg := sync.WaitGroup{}

	for i := 0; i < 2; i++ {
		wg.Add(1)
		go func(threadID int) {
			row := db.QueryRow(query)
			err = row.Err()
			if err != nil {
				log.Fatalf("[%d] Error: %v", threadID, err)
			}

			var item json.RawMessage
			err = row.Scan(&item)
			if err != nil {
				log.Fatalf("[%d] Error: %v", threadID, err)
			}

			log.Printf("[%d] Result: %s", threadID, string(item))

			wg.Done()
		}(i)
	}
	wg.Wait()
}
  1. go mod init pgstac_repro
  2. go get github.com/lib/pq
  3. go run main.go

This will spin up two threads and try to run the same search simultaneously on both. For me this gives the following pretty reliably:

2024/01/18 22:34:44 Successfully connected!
2024/01/18 22:34:44 Search query: "SELECT search('{\"limit\": 1}'::jsonb);"
2024/01/18 22:34:44 [1] Result: {"next": null, "prev": null, "type": "FeatureCollection", "context": {"limit": 1, "returned": 0}, "features": []}
2024/01/18 22:34:44 [0] Error: pq: syntax error at or near "LIMIT"
exit status 1

One of them succeeds, the other gives a syntax error with the same query.

The postgres logs show

2024-01-18 22:34:44.440 UTC [96] STATEMENT:  SELECT search('{"limit": 1}'::jsonb);
2024-01-18 22:34:44.442 UTC [96] LOG:  QUERY:
                SELECT * FROM items
                WHERE  TRUE
                ORDER BY
                LIMIT '2'

2024-01-18 22:34:44.442 UTC [96] CONTEXT:  PL/pgSQL function search_rows(text,text,text[],integer) line 82 at RAISE
        SQL statement "SELECT jsonb_agg(format_item(i, _fields, hydrate))                      FROM search_rows(
                full_where,
                orderby,
                search_where.partitions,
                _querylimit
            ) as i"
        PL/pgSQL function search(jsonb) line 69 at SQL statement
2024-01-18 22:34:44.442 UTC [96] STATEMENT:  SELECT search('{"limit": 1}'::jsonb);
2024-01-18 22:34:44.443 UTC [96] ERROR:  syntax error at or near "LIMIT" at character 77
2024-01-18 22:34:44.443 UTC [96] QUERY:
                SELECT * FROM items
                WHERE  TRUE
                ORDER BY
                LIMIT '2'

So, a different error but similar behaviour.

Again, I can't see exactly where the code this could be happening, but rerunning the same program again will not trigger it, you need to either change the query or restart the database to trigger the bug again. I guess this means the problem is related to the query cache/statistics tables.

Any help would be appreciated. Let me know if there are any other details I can provide.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions