func queryWithID(tx *sql.Tx, query string, args ...interface{}) (uint32, error) {
	var id uint32
	if err := tx.QueryRow(query, args...).Scan(&id); err != nil {
		return 0, err
	}
	return id, nil
}
queryWithID executes the specified SQL query with the given arguments,
expecting a single-row, single-column result containing an ID. If the query
succeeds, the ID from the result is returned.
package psql
import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"strings"
	"time"
	"github.com/gogo/protobuf/proto"
	abci "github.com/tendermint/tendermint/abci/types"
	"github.com/tendermint/tendermint/internal/state/indexer"
	"github.com/tendermint/tendermint/libs/pubsub/query"
	"github.com/tendermint/tendermint/types"
)
const (
	tableBlocks     = "blocks"
	tableTxResults  = "tx_results"
	tableEvents     = "events"
	tableAttributes = "attributes"
	driverName      = "postgres"
)
type EventSink struct {
	store   *sql.DB
	chainID string
}
func NewEventSink(connStr, chainID string) (*EventSink, error) {
	db, err := sql.Open(driverName, connStr)
	if err != nil {
		return nil, err
	}
	return &EventSink{
		store:   db,
		chainID: chainID,
	}, nil
}
func (es *EventSink) DB() *sql.DB { return es.store }
func (es *EventSink) Type() indexer.EventSinkType { return indexer.PSQL }
func runInTransaction(db *sql.DB, query func(*sql.Tx) error) error {
	dbtx, err := db.Begin()
	if err != nil {
		return err
	}
	if err := query(dbtx); err != nil {
		_ = dbtx.Rollback()  
		return err
	}
	return dbtx.Commit()
}