connection.go 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815
  1. package pgserver
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/binary"
  6. "encoding/hex"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "log"
  11. "net"
  12. "os"
  13. "regexp"
  14. "sort"
  15. "strconv"
  16. "strings"
  17. "sync/atomic"
  18. "github.com/danfragoso/pizzasql-next/pkg/analyzer"
  19. "github.com/danfragoso/pizzasql-next/pkg/executor"
  20. "github.com/danfragoso/pizzasql-next/pkg/lexer"
  21. "github.com/danfragoso/pizzasql-next/pkg/parser"
  22. "github.com/danfragoso/pizzasql-next/pkg/pgerror"
  23. "github.com/danfragoso/pizzasql-next/pkg/storage"
  24. "github.com/danfragoso/pizzasql-next/pkg/version"
  25. )
  26. // Connection represents a client connection
  27. type Connection struct {
  28. conn net.Conn
  29. reader *bufio.Reader
  30. writer *bufio.Writer
  31. executor *executor.Executor
  32. schema *storage.SchemaManager
  33. table *storage.TableManager
  34. dbManager *storage.DatabaseManager
  35. database string
  36. params map[string]string
  37. txStatus byte
  38. quiet bool // Disable query logging
  39. statements map[string]*preparedStatement
  40. portals map[string]*portal
  41. extendedFailed bool
  42. backendPID int32
  43. // extendedCycle is true between Parse/Bind/Execute/Describe/Close and the
  44. // next Sync. Notifications are not interleaved into an extended-protocol
  45. // sequence; they are held until Sync.
  46. extendedCycle bool
  47. // catalogFallback serves catalog emulation before the executor exists, when
  48. // a connection has managers but has not completed startup.
  49. catalogFallback *storage.Session
  50. }
  51. // backendPIDSeq gives each connection a distinct synthetic backend PID. It is
  52. // seeded with the process ID so NotificationResponse frames look plausible and
  53. // do not collide across server processes.
  54. var backendPIDSeq atomic.Int32
  55. func nextBackendPID() int32 {
  56. return int32(os.Getpid()) + backendPIDSeq.Add(1)
  57. }
  58. type preparedStatement struct {
  59. query string
  60. // paramOIDs is the negotiated parameter type list: the client's non-zero
  61. // Parse OIDs plus inferred types for the zeros. Describe reports it and
  62. // Bind decodes with it.
  63. paramOIDs []int32
  64. }
  65. type portal struct {
  66. query string
  67. executed bool
  68. // resultFormats is the Bind result format list exactly as the client sent
  69. // it: empty (all text), one entry that repeats for every column, or one
  70. // entry per column. It is resolved against the produced result at Execute.
  71. resultFormats []int16
  72. }
  73. // NewConnection creates a new connection handler
  74. func NewConnection(conn net.Conn, dbManager *storage.DatabaseManager, quiet bool) *Connection {
  75. return &Connection{
  76. conn: conn,
  77. reader: bufio.NewReader(conn),
  78. writer: bufio.NewWriter(conn),
  79. dbManager: dbManager,
  80. params: make(map[string]string),
  81. statements: make(map[string]*preparedStatement),
  82. portals: make(map[string]*portal),
  83. txStatus: TxStatusIdle,
  84. quiet: quiet,
  85. backendPID: nextBackendPID(),
  86. }
  87. }
  88. // Handle processes the connection
  89. func (c *Connection) Handle() error {
  90. defer func() {
  91. if c.executor != nil {
  92. if err := c.executor.Close(); err != nil && !c.quiet {
  93. log.Printf("failed to close session: %v", err)
  94. }
  95. }
  96. c.conn.Close()
  97. }()
  98. // First, check for SSL request (sent before startup message)
  99. // SSL request is 8 bytes: length(4) + code(4) where code = 80877103
  100. firstBytes := make([]byte, 8)
  101. n, err := io.ReadFull(c.reader, firstBytes)
  102. if err != nil {
  103. return fmt.Errorf("failed to read initial bytes: %w", err)
  104. }
  105. // Check if it's an SSL request (code 80877103 = 0x04D2162F)
  106. if n == 8 {
  107. length := binary.BigEndian.Uint32(firstBytes[0:4])
  108. code := binary.BigEndian.Uint32(firstBytes[4:8])
  109. if length == 8 && code == 80877103 {
  110. // SSL request - we don't support SSL, send 'N'
  111. if !c.quiet {
  112. log.Printf("Client requested SSL, sending rejection")
  113. }
  114. if _, err := c.conn.Write([]byte{'N'}); err != nil {
  115. return fmt.Errorf("failed to send SSL rejection: %w", err)
  116. }
  117. // Now read the actual startup message
  118. } else {
  119. // Not SSL request, this is part of startup message
  120. // We need to prepend these bytes back for ReadStartupMessage
  121. // Create a multi-reader that first reads our buffered bytes, then continues with the reader
  122. c.reader = bufio.NewReader(io.MultiReader(bytes.NewReader(firstBytes), c.reader))
  123. }
  124. }
  125. // Read startup message
  126. if !c.quiet {
  127. log.Printf("Reading startup message...")
  128. }
  129. params, err := ReadStartupMessage(c.reader)
  130. if err != nil {
  131. return fmt.Errorf("failed to read startup message: %w", err)
  132. }
  133. c.params = params
  134. if !c.quiet {
  135. log.Printf("Startup params: %+v", params)
  136. }
  137. // Get database name from params (default to "pizzasql")
  138. dbName := params["database"]
  139. if dbName == "" {
  140. dbName = "pizzasql"
  141. }
  142. c.database = dbName
  143. if !c.quiet {
  144. log.Printf("New connection: user=%s database=%s", params["user"], dbName)
  145. }
  146. // Initialize database
  147. if err := c.initDatabase(dbName); err != nil {
  148. c.sendError("FATAL", ErrCodeConnectionFailure, fmt.Sprintf("Failed to initialize database: %v", err))
  149. return err
  150. }
  151. // Send authentication OK (no auth for now)
  152. if err := c.sendAuthenticationOk(); err != nil {
  153. return err
  154. }
  155. // Send parameter status messages
  156. if err := c.sendParameterStatus("server_version", version.PostgreSQLCompatVersion+" (PizzaSQL)"); err != nil {
  157. return err
  158. }
  159. // Build identity is a separate, custom ParameterStatus so the PostgreSQL
  160. // compatibility string above stays stable for version-sniffing drivers.
  161. if err := c.sendParameterStatus("pizzasql.version", version.String()); err != nil {
  162. return err
  163. }
  164. if err := c.sendParameterStatus("pizzasql.commit", version.Commit); err != nil {
  165. return err
  166. }
  167. if err := c.sendParameterStatus("pizzasql.proxy_errors", "1"); err != nil {
  168. return err
  169. }
  170. if err := c.sendParameterStatus("server_encoding", "UTF8"); err != nil {
  171. return err
  172. }
  173. if err := c.sendParameterStatus("client_encoding", "UTF8"); err != nil {
  174. return err
  175. }
  176. if err := c.sendParameterStatus("DateStyle", "ISO, MDY"); err != nil {
  177. return err
  178. }
  179. if err := c.sendParameterStatus("TimeZone", "UTC"); err != nil {
  180. return err
  181. }
  182. // Send backend key data (for cancellation - we don't implement this yet)
  183. if err := c.sendBackendKeyData(c.backendPID, 67890); err != nil {
  184. return err
  185. }
  186. // Send ready for query
  187. if err := c.sendReadyForQuery(); err != nil {
  188. return err
  189. }
  190. // Read messages on a separate goroutine so an idle listener can receive
  191. // asynchronous NotificationResponse frames while blocked waiting for input.
  192. // Only this goroutine writes to c.writer, which keeps frame order intact.
  193. type readResult struct {
  194. msg *Message
  195. err error
  196. }
  197. inbox := make(chan readResult, 16)
  198. done := make(chan struct{})
  199. defer close(done)
  200. go func() {
  201. for {
  202. msg, err := ReadMessage(c.reader)
  203. select {
  204. case inbox <- readResult{msg: msg, err: err}:
  205. case <-done:
  206. return
  207. }
  208. if err != nil {
  209. return
  210. }
  211. }
  212. }()
  213. notifications := c.executor.NotificationChannel()
  214. overflow := c.executor.NotificationOverflow()
  215. for {
  216. // Do not interleave notifications into an extended-protocol cycle. The
  217. // channel is disabled until Sync closes the cycle.
  218. var notifyCh <-chan storage.Notification
  219. if !c.extendedCycle {
  220. notifyCh = notifications
  221. }
  222. select {
  223. case res := <-inbox:
  224. if res.err != nil {
  225. if res.err == io.EOF {
  226. log.Printf("Connection closed by client")
  227. return nil
  228. }
  229. return fmt.Errorf("failed to read message: %w", res.err)
  230. }
  231. switch res.msg.Type {
  232. case MsgParse, MsgBind, MsgDescribe, MsgExecute, MsgClose:
  233. c.extendedCycle = true
  234. }
  235. if err := c.handleMessage(res.msg); err != nil {
  236. if err == io.EOF {
  237. log.Printf("Connection closed normally")
  238. return nil
  239. }
  240. log.Printf("Error handling message: %v", err)
  241. return err
  242. }
  243. case n := <-notifyCh:
  244. if err := c.sendNotification(n); err != nil {
  245. return err
  246. }
  247. if err := c.writer.Flush(); err != nil {
  248. return err
  249. }
  250. case <-overflow:
  251. return fmt.Errorf("notification queue overflow: slow consumer disconnected")
  252. }
  253. }
  254. }
  255. // initDatabase initializes the database connection
  256. func (c *Connection) initDatabase(dbName string) error {
  257. db, err := c.dbManager.GetDatabase(dbName)
  258. if err != nil {
  259. return err
  260. }
  261. c.schema = db.Schema
  262. c.table = db.Table
  263. c.executor = executor.New(db.Schema, db.Table)
  264. c.executor.SetBackendPID(c.backendPID)
  265. c.executor.SetNotificationHub(db.Hub)
  266. c.executor.SyncCatalog()
  267. return nil
  268. }
  269. // handleMessage processes a client message
  270. func (c *Connection) handleMessage(msg *Message) error {
  271. if c.extendedFailed && msg.Type != MsgSync && msg.Type != MsgFlush && msg.Type != MsgTerminate {
  272. return nil
  273. }
  274. switch msg.Type {
  275. case MsgProxyError:
  276. return c.handleProxyError(msg)
  277. case MsgQuery:
  278. return c.handleQuery(msg)
  279. case MsgTerminate:
  280. log.Printf("Client requested termination")
  281. return io.EOF
  282. case MsgParse:
  283. return c.handleParse(msg)
  284. case MsgBind:
  285. return c.handleBind(msg)
  286. case MsgDescribe:
  287. return c.handleDescribe(msg)
  288. case MsgExecute:
  289. return c.handleExecute(msg)
  290. case MsgClose:
  291. return c.handleClose(msg)
  292. case MsgFlush:
  293. return c.writer.Flush()
  294. case MsgSync:
  295. c.extendedFailed = false
  296. c.extendedCycle = false
  297. if err := c.sendReadyForQuery(); err != nil {
  298. return err
  299. }
  300. return c.drainNotifications()
  301. default:
  302. log.Printf("Unknown message type: %c (%d)", msg.Type, msg.Type)
  303. c.sendError("ERROR", ErrCodeProtocolViolation, fmt.Sprintf("Unknown message type: %c", msg.Type))
  304. return c.sendReadyForQuery()
  305. }
  306. }
  307. // handleQuery processes a simple query
  308. func (c *Connection) handleQuery(msg *Message) error {
  309. // A Query message carries a single NUL-terminated query string.
  310. if len(msg.Data) == 0 || msg.Data[len(msg.Data)-1] != 0 {
  311. c.sendError("ERROR", ErrCodeProtocolViolation, "invalid Query message: missing null terminator")
  312. return c.sendReadyForQuery()
  313. }
  314. sql := string(msg.Data[:len(msg.Data)-1])
  315. if !c.quiet {
  316. log.Printf("Query: %s", sql)
  317. }
  318. // Handle empty query
  319. sqlTrimmed := strings.TrimSpace(sql)
  320. if sqlTrimmed == "" || sqlTrimmed == ";" {
  321. if err := c.sendEmptyQueryResponse(); err != nil {
  322. return err
  323. }
  324. return c.sendReadyForQuery()
  325. }
  326. // Handle special PostgreSQL system queries that drivers send
  327. singleStatement := isSingleStatementSQL(sql)
  328. // In a failed transaction only ROLLBACK (or ROLLBACK TO SAVEPOINT) is
  329. // accepted. Gate before honoring the special driver queries below so they
  330. // return 25P02 instead of a result. Multi-statement batches are gated
  331. // per statement in the execution loop below.
  332. if c.txStatus == TxStatusFailed && singleStatement && !isRollbackStatement(sql) {
  333. c.sendError("ERROR", ErrCodeTransactionAborted, "current transaction is aborted, commands ignored until end of transaction block")
  334. return c.sendReadyForQuery()
  335. }
  336. // Recognize only complete initialization-query token sequences.
  337. if singleStatement {
  338. switch kind := systemQueryKind(sql); kind {
  339. case "version":
  340. return c.handleVersionQuery()
  341. case "current_user":
  342. return c.handleCurrentUserQuery()
  343. case "server_version", "server_encoding", "client_encoding":
  344. return c.handleShowCommand(strings.ToUpper(kind))
  345. }
  346. }
  347. if result, handled, err := c.catalogResult(sql); handled {
  348. if err != nil {
  349. c.sendError("ERROR", ErrCodeInternalError, err.Error())
  350. return c.sendReadyForQuery()
  351. }
  352. if err := c.sendTabularResult(result, "SELECT", nil); err != nil {
  353. return err
  354. }
  355. return c.sendReadyForQuery()
  356. }
  357. // Parse the complete batch before executing its first statement. This keeps
  358. // unsupported trailing clauses from turning into committed writes.
  359. l := lexer.New(sql)
  360. p := parser.New(l)
  361. stmts, err := p.ParseMultiple()
  362. if err != nil {
  363. code := ErrCodeSyntaxError
  364. if errors.Is(err, pgerror.ErrFeatureNotSupported) {
  365. code = ErrCodeFeatureNotSupported
  366. }
  367. if c.txStatus == TxStatusInBlock {
  368. c.txStatus = TxStatusFailed
  369. }
  370. c.sendError("ERROR", code, fmt.Sprintf("Syntax error: %v", err))
  371. return c.sendReadyForQuery()
  372. }
  373. for _, stmt := range stmts {
  374. if c.txStatus == TxStatusFailed {
  375. if _, rollback := stmt.(*parser.RollbackStmt); !rollback {
  376. c.sendError("ERROR", ErrCodeTransactionAborted, "current transaction is aborted, commands ignored until end of transaction block")
  377. return c.sendReadyForQuery()
  378. }
  379. }
  380. result, err := c.executor.Execute(stmt)
  381. if err != nil && isIdleRollback(stmt, c.txStatus, err) {
  382. result, err = executor.NewResult("ROLLBACK"), nil
  383. }
  384. if err != nil {
  385. code := ErrCodeInternalError
  386. message := fmt.Sprintf("Execution error: %v", err)
  387. var primaryKeyErr *storage.PrimaryKeyViolationError
  388. var uniqueErr *storage.UniqueViolationError
  389. var notNullErr *storage.NotNullViolationError
  390. var checkErr *storage.CheckViolationError
  391. var foreignKeyErr *storage.ForeignKeyViolationError
  392. if errors.Is(err, storage.ErrSerialization) {
  393. code = ErrCodeSerializationFailure
  394. c.txStatus = TxStatusIdle
  395. } else if errors.Is(err, pgerror.ErrInvalidText) {
  396. code = ErrCodeInvalidText
  397. if c.txStatus == TxStatusInBlock {
  398. c.txStatus = TxStatusFailed
  399. }
  400. } else if errors.Is(err, pgerror.ErrInvalidParameter) {
  401. code = ErrCodeInvalidParameter
  402. if c.txStatus == TxStatusInBlock {
  403. c.txStatus = TxStatusFailed
  404. }
  405. } else if errors.Is(err, pgerror.ErrDatatypeMismatch) {
  406. code = ErrCodeDatatypeMismatch
  407. if c.txStatus == TxStatusInBlock {
  408. c.txStatus = TxStatusFailed
  409. }
  410. } else if analysisErr := analysisTypeMismatch(err); analysisErr {
  411. code = ErrCodeDatatypeMismatch
  412. if c.txStatus == TxStatusInBlock {
  413. c.txStatus = TxStatusFailed
  414. }
  415. } else if errors.As(err, &notNullErr) {
  416. code = "23502"
  417. if _, commit := stmt.(*parser.CommitStmt); commit {
  418. c.txStatus = TxStatusIdle
  419. } else if c.txStatus == TxStatusInBlock {
  420. c.txStatus = TxStatusFailed
  421. }
  422. } else if errors.As(err, &checkErr) {
  423. code = ErrCodeCheckViolation
  424. if _, commit := stmt.(*parser.CommitStmt); commit {
  425. c.txStatus = TxStatusIdle
  426. } else if c.txStatus == TxStatusInBlock {
  427. c.txStatus = TxStatusFailed
  428. }
  429. } else if errors.As(err, &foreignKeyErr) {
  430. code = ErrCodeForeignKeyViolation
  431. if _, commit := stmt.(*parser.CommitStmt); commit {
  432. c.txStatus = TxStatusIdle
  433. } else if c.txStatus == TxStatusInBlock {
  434. c.txStatus = TxStatusFailed
  435. }
  436. } else if errors.As(err, &uniqueErr) || errors.As(err, &primaryKeyErr) {
  437. code = ErrCodeUniqueViolation
  438. if uniqueErr != nil {
  439. message = fmt.Sprintf("Execution error: UNIQUE constraint failed: %s", uniqueErr.Constraint)
  440. }
  441. if _, commit := stmt.(*parser.CommitStmt); commit {
  442. c.txStatus = TxStatusIdle
  443. } else if c.txStatus == TxStatusInBlock {
  444. c.txStatus = TxStatusFailed
  445. }
  446. } else if errors.Is(err, pgerror.ErrFeatureNotSupported) || errors.Is(err, executor.ErrUnsupportedFeature) {
  447. code = ErrCodeFeatureNotSupported
  448. if c.txStatus == TxStatusInBlock {
  449. c.txStatus = TxStatusFailed
  450. }
  451. } else if _, commit := stmt.(*parser.CommitStmt); commit {
  452. // A failed COMMIT has already rolled the transaction back in
  453. // storage; leaving the session in the failed state would make
  454. // every following statement (including ROLLBACK) fail.
  455. c.txStatus = TxStatusIdle
  456. } else if c.txStatus == TxStatusInBlock {
  457. c.txStatus = TxStatusFailed
  458. }
  459. c.sendError("ERROR", code, message)
  460. return c.sendReadyForQuery()
  461. }
  462. if err := c.sendResult(result, stmt, wireColumnTypes(result), nil); err != nil {
  463. return err
  464. }
  465. if result.LSN > 0 {
  466. if err := c.sendLSN(result.LSN); err != nil {
  467. return err
  468. }
  469. }
  470. }
  471. return c.sendReadyForQuery()
  472. }
  473. func (c *Connection) handleParse(msg *Message) error {
  474. if c.extendedFailed {
  475. return nil
  476. }
  477. name, pos, err := readCString(msg.Data, 0)
  478. if err != nil {
  479. return c.failExtended(ErrCodeProtocolViolation, err)
  480. }
  481. query, pos, err := readCString(msg.Data, pos)
  482. if err != nil || pos+2 > len(msg.Data) {
  483. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Parse message"))
  484. }
  485. count := int(binary.BigEndian.Uint16(msg.Data[pos : pos+2]))
  486. pos += 2
  487. if pos+count*4 != len(msg.Data) {
  488. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Parse parameter list"))
  489. }
  490. oids := make([]int32, count)
  491. for i := range oids {
  492. oids[i] = int32(binary.BigEndian.Uint32(msg.Data[pos : pos+4]))
  493. pos += 4
  494. }
  495. if !isSingleStatementSQL(query) {
  496. return c.failExtended(ErrCodeSyntaxError, fmt.Errorf("prepared statements must contain one command"))
  497. }
  498. paramOIDs, err := c.negotiateParameterOIDs(query, oids)
  499. if err != nil {
  500. return c.failExtended(ErrCodeProgramLimitExceeded, err)
  501. }
  502. c.statements[name] = &preparedStatement{query: query, paramOIDs: paramOIDs}
  503. return c.writeMessage(MsgParseComplete, nil)
  504. }
  505. func (c *Connection) handleBind(msg *Message) error {
  506. if c.extendedFailed {
  507. return nil
  508. }
  509. portalName, pos, err := readCString(msg.Data, 0)
  510. if err != nil {
  511. return c.failExtended(ErrCodeProtocolViolation, err)
  512. }
  513. statementName, pos, err := readCString(msg.Data, pos)
  514. if err != nil {
  515. return c.failExtended(ErrCodeProtocolViolation, err)
  516. }
  517. statement, ok := c.statements[statementName]
  518. if !ok {
  519. return c.failExtended(ErrCodeInvalidParameter, fmt.Errorf("prepared statement %q does not exist", statementName))
  520. }
  521. formats, pos, err := readInt16List(msg.Data, pos)
  522. if err != nil || pos+2 > len(msg.Data) {
  523. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Bind format list"))
  524. }
  525. paramCount := int(binary.BigEndian.Uint16(msg.Data[pos : pos+2]))
  526. pos += 2
  527. if len(formats) > 1 && len(formats) != paramCount {
  528. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("Bind parameter format count does not match parameters"))
  529. }
  530. for _, format := range formats {
  531. if format != 0 && format != 1 {
  532. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Bind parameter format code"))
  533. }
  534. }
  535. params := make([]boundParameter, paramCount)
  536. for i := range params {
  537. if pos+4 > len(msg.Data) {
  538. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Bind parameter"))
  539. }
  540. length := int32(binary.BigEndian.Uint32(msg.Data[pos : pos+4]))
  541. pos += 4
  542. params[i].oid = parameterOID(statement.paramOIDs, i)
  543. params[i].format = parameterFormat(formats, i)
  544. if length == -1 {
  545. params[i].null = true
  546. continue
  547. }
  548. if length < 0 || pos+int(length) > len(msg.Data) {
  549. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Bind parameter length"))
  550. }
  551. params[i].value = append([]byte(nil), msg.Data[pos:pos+int(length)]...)
  552. pos += int(length)
  553. }
  554. resultFormats, pos, err := readInt16List(msg.Data, pos)
  555. if err != nil || pos != len(msg.Data) {
  556. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Bind result format list"))
  557. }
  558. for _, format := range resultFormats {
  559. if format != 0 && format != 1 {
  560. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Bind result format code"))
  561. }
  562. }
  563. query, err := bindQuery(statement.query, params)
  564. if err != nil {
  565. code := ErrCodeInvalidParameter
  566. if errors.Is(err, pgerror.ErrFeatureNotSupported) {
  567. code = ErrCodeFeatureNotSupported
  568. }
  569. if errors.Is(err, pgerror.ErrInvalidText) {
  570. code = ErrCodeInvalidText
  571. }
  572. if errors.Is(err, pgerror.ErrInvalidParameter) {
  573. code = ErrCodeInvalidParameter
  574. }
  575. return c.failExtended(code, err)
  576. }
  577. c.portals[portalName] = &portal{query: query, resultFormats: resultFormats}
  578. return c.writeMessage(MsgBindComplete, nil)
  579. }
  580. func (c *Connection) handleDescribe(msg *Message) error {
  581. if c.extendedFailed {
  582. return nil
  583. }
  584. if len(msg.Data) < 2 {
  585. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Describe message"))
  586. }
  587. name, pos, err := readCString(msg.Data, 1)
  588. if err != nil || pos != len(msg.Data) {
  589. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Describe name"))
  590. }
  591. switch msg.Data[0] {
  592. case 'S':
  593. statement, ok := c.statements[name]
  594. if !ok {
  595. return c.failExtended(ErrCodeInvalidParameter, fmt.Errorf("prepared statement %q does not exist", name))
  596. }
  597. if err := c.sendParameterDescription(statement.paramOIDs); err != nil {
  598. return err
  599. }
  600. case 'P':
  601. // PostgreSQL reports parameter types only for Describe('S'). Portal
  602. // Describe returns row metadata (here NoData) without a
  603. // ParameterDescription.
  604. if _, ok := c.portals[name]; !ok {
  605. return c.failExtended(ErrCodeInvalidParameter, fmt.Errorf("portal %q does not exist", name))
  606. }
  607. default:
  608. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Describe target"))
  609. }
  610. // Row metadata requires analysis without side effects. Return NoData for
  611. // compatibility; Execute still emits the real RowDescription. This is the
  612. // pre-0.4.0 behavior used by common extended-protocol clients.
  613. return c.writeMessage(MsgNoData, nil)
  614. }
  615. func (c *Connection) handleExecute(msg *Message) error {
  616. if c.extendedFailed {
  617. return nil
  618. }
  619. name, pos, err := readCString(msg.Data, 0)
  620. if err != nil || pos+4 != len(msg.Data) {
  621. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Execute message"))
  622. }
  623. portal, ok := c.portals[name]
  624. if !ok {
  625. return c.failExtended(ErrCodeInvalidParameter, fmt.Errorf("portal %q does not exist", name))
  626. }
  627. if portal.executed {
  628. return c.failExtended(ErrCodeFeatureNotSupported, fmt.Errorf("portal can only be executed once"))
  629. }
  630. maxRows := int32(binary.BigEndian.Uint32(msg.Data[pos : pos+4]))
  631. if maxRows < 0 {
  632. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Execute row limit"))
  633. }
  634. // Check the transaction state before catalog emulation. Catalog queries do
  635. // not all parse as regular PizzaSQL statements, but must still return 25P02
  636. // while the transaction is aborted.
  637. if c.txStatus == TxStatusFailed && !isRollbackStatement(portal.query) {
  638. return c.failExtended(ErrCodeTransactionAborted, fmt.Errorf("current transaction is aborted, commands ignored until end of transaction block"))
  639. }
  640. if maxRows != 0 {
  641. return c.failExtended(ErrCodeFeatureNotSupported, fmt.Errorf("bounded Execute is not supported; use maxRows=0"))
  642. }
  643. portal.executed = true
  644. if result, handled, catalogErr := c.catalogResult(portal.query); handled {
  645. if catalogErr != nil {
  646. return c.failExtended(ErrCodeInternalError, catalogErr)
  647. }
  648. return c.sendTabularResult(result, "SELECT", portal.resultFormats)
  649. }
  650. l := lexer.New(portal.query)
  651. stmt, err := parser.New(l).Parse()
  652. if err != nil {
  653. code := ErrCodeSyntaxError
  654. if errors.Is(err, pgerror.ErrFeatureNotSupported) {
  655. code = ErrCodeFeatureNotSupported
  656. if c.txStatus == TxStatusInBlock {
  657. c.txStatus = TxStatusFailed
  658. }
  659. }
  660. return c.failExtended(code, fmt.Errorf("syntax error: %w", err))
  661. }
  662. result, err := c.executor.Execute(stmt)
  663. if err != nil && isIdleRollback(stmt, c.txStatus, err) {
  664. result, err = executor.NewResult("ROLLBACK"), nil
  665. }
  666. if err != nil {
  667. code := ErrCodeInternalError
  668. var primaryKeyErr *storage.PrimaryKeyViolationError
  669. var uniqueErr *storage.UniqueViolationError
  670. var notNullErr *storage.NotNullViolationError
  671. var checkErr *storage.CheckViolationError
  672. var foreignKeyErr *storage.ForeignKeyViolationError
  673. if errors.Is(err, storage.ErrSerialization) {
  674. code = ErrCodeSerializationFailure
  675. c.txStatus = TxStatusIdle
  676. } else if errors.Is(err, pgerror.ErrInvalidText) {
  677. code = ErrCodeInvalidText
  678. if c.txStatus == TxStatusInBlock {
  679. c.txStatus = TxStatusFailed
  680. }
  681. } else if errors.Is(err, pgerror.ErrInvalidParameter) {
  682. code = ErrCodeInvalidParameter
  683. if c.txStatus == TxStatusInBlock {
  684. c.txStatus = TxStatusFailed
  685. }
  686. } else if errors.Is(err, pgerror.ErrDatatypeMismatch) {
  687. code = ErrCodeDatatypeMismatch
  688. if c.txStatus == TxStatusInBlock {
  689. c.txStatus = TxStatusFailed
  690. }
  691. } else if analysisTypeMismatch(err) {
  692. code = ErrCodeDatatypeMismatch
  693. if c.txStatus == TxStatusInBlock {
  694. c.txStatus = TxStatusFailed
  695. }
  696. } else if errors.As(err, &notNullErr) {
  697. code = "23502"
  698. if _, commit := stmt.(*parser.CommitStmt); commit {
  699. c.txStatus = TxStatusIdle
  700. } else if c.txStatus == TxStatusInBlock {
  701. c.txStatus = TxStatusFailed
  702. }
  703. } else if errors.As(err, &checkErr) {
  704. code = ErrCodeCheckViolation
  705. if _, commit := stmt.(*parser.CommitStmt); commit {
  706. c.txStatus = TxStatusIdle
  707. } else if c.txStatus == TxStatusInBlock {
  708. c.txStatus = TxStatusFailed
  709. }
  710. } else if errors.As(err, &foreignKeyErr) {
  711. code = ErrCodeForeignKeyViolation
  712. if _, commit := stmt.(*parser.CommitStmt); commit {
  713. c.txStatus = TxStatusIdle
  714. } else if c.txStatus == TxStatusInBlock {
  715. c.txStatus = TxStatusFailed
  716. }
  717. } else if errors.As(err, &uniqueErr) || errors.As(err, &primaryKeyErr) {
  718. code = ErrCodeUniqueViolation
  719. if _, commit := stmt.(*parser.CommitStmt); commit {
  720. c.txStatus = TxStatusIdle
  721. } else if c.txStatus == TxStatusInBlock {
  722. c.txStatus = TxStatusFailed
  723. }
  724. } else if errors.Is(err, pgerror.ErrFeatureNotSupported) || errors.Is(err, executor.ErrUnsupportedFeature) {
  725. code = ErrCodeFeatureNotSupported
  726. if c.txStatus == TxStatusInBlock {
  727. c.txStatus = TxStatusFailed
  728. }
  729. } else if _, commit := stmt.(*parser.CommitStmt); commit {
  730. c.txStatus = TxStatusIdle
  731. } else if c.txStatus == TxStatusInBlock {
  732. c.txStatus = TxStatusFailed
  733. }
  734. if uniqueErr != nil {
  735. return c.failExtended(code, fmt.Errorf("execution error: UNIQUE constraint failed: %s", uniqueErr.Constraint))
  736. }
  737. return c.failExtended(code, fmt.Errorf("execution error: %w", err))
  738. }
  739. columnTypes := wireColumnTypes(result)
  740. formats, formatErr := c.resolveResultFormats(portal.resultFormats, columnTypes, len(result.Columns))
  741. if formatErr != nil {
  742. return c.failResultFormat(formatErr)
  743. }
  744. if err := c.sendResult(result, stmt, columnTypes, formats); err != nil {
  745. return err
  746. }
  747. if result.LSN > 0 {
  748. return c.sendLSN(result.LSN)
  749. }
  750. return nil
  751. }
  752. // catalogSession is the catalog view this connection serves. The executor's
  753. // session is authoritative because it resolves against the transaction-scoped
  754. // DDL overlay, so catalog emulation inside a transaction sees staged tables,
  755. // columns, and indexes. The fallback only covers a connection that has not
  756. // completed startup yet.
  757. func (c *Connection) catalogSession() *storage.Session {
  758. if c.executor != nil {
  759. return c.executor.Session()
  760. }
  761. if c.schema == nil || c.table == nil {
  762. return nil
  763. }
  764. if c.catalogFallback == nil {
  765. c.catalogFallback = storage.NewSession(c.schema, c.table)
  766. }
  767. return c.catalogFallback
  768. }
  769. var catalogFilterPattern = regexp.MustCompile(`(?i)\b(table_name|tablename|table_schema|schemaname|constraint_name|indexname)\s*=\s*'((?:''|[^'])*)'`)
  770. func (c *Connection) catalogResult(sql string) (*executor.Result, bool, error) {
  771. if !isSingleStatementSQL(sql) {
  772. return nil, false, nil
  773. }
  774. source := catalogSource(sql)
  775. if source == "" {
  776. return nil, false, nil
  777. }
  778. session := c.catalogSession()
  779. if session == nil {
  780. return nil, false, nil
  781. }
  782. tables, err := session.ListTables()
  783. if err != nil {
  784. return nil, true, err
  785. }
  786. rows := make([]map[string]interface{}, 0)
  787. switch source {
  788. case "INFORMATION_SCHEMA.TABLES":
  789. for _, table := range tables {
  790. rows = append(rows, map[string]interface{}{
  791. "table_catalog": c.database, "table_schema": "public", "table_name": table, "table_type": "BASE TABLE",
  792. })
  793. }
  794. case "PG_TABLES":
  795. for _, table := range tables {
  796. indexes, _ := session.ListTableIndexes(table)
  797. rows = append(rows, map[string]interface{}{
  798. "schemaname": "public", "tablename": table, "tableowner": c.params["user"], "tablespace": nil,
  799. "hasindexes": len(indexes) > 0, "hasrules": false, "hastriggers": false, "rowsecurity": false,
  800. })
  801. }
  802. case "INFORMATION_SCHEMA.COLUMNS":
  803. for _, table := range tables {
  804. schema, schemaErr := session.GetSchema(table)
  805. if schemaErr != nil {
  806. continue
  807. }
  808. for i, column := range schema.Columns {
  809. rows = append(rows, map[string]interface{}{
  810. "table_catalog": c.database, "table_schema": "public", "table_name": table,
  811. "column_name": column.Name, "ordinal_position": int64(i + 1), "column_default": column.DefaultLiteral(),
  812. "is_nullable": yesNo(column.Nullable), "data_type": strings.ToLower(column.Type),
  813. })
  814. }
  815. }
  816. case "INFORMATION_SCHEMA.TABLE_CONSTRAINTS", "INFORMATION_SCHEMA.KEY_COLUMN_USAGE":
  817. for _, table := range tables {
  818. schema, schemaErr := session.GetSchema(table)
  819. if schemaErr != nil || schema.UsesSyntheticRowID() {
  820. continue
  821. }
  822. columns := schema.PrimaryKeyList()
  823. if source == "INFORMATION_SCHEMA.TABLE_CONSTRAINTS" {
  824. rows = append(rows, map[string]interface{}{
  825. "constraint_catalog": c.database, "constraint_schema": "public", "constraint_name": table + "_pkey",
  826. "table_catalog": c.database, "table_schema": "public", "table_name": table,
  827. "constraint_type": "PRIMARY KEY", "is_deferrable": "NO", "initially_deferred": "NO",
  828. })
  829. continue
  830. }
  831. // KEY_COLUMN_USAGE reports one row per key column, in key order.
  832. for i, column := range columns {
  833. rows = append(rows, map[string]interface{}{
  834. "constraint_catalog": c.database, "constraint_schema": "public", "constraint_name": table + "_pkey",
  835. "table_catalog": c.database, "table_schema": "public", "table_name": table,
  836. "column_name": column, "ordinal_position": int64(i + 1),
  837. })
  838. }
  839. }
  840. case "PG_INDEXES":
  841. for _, table := range tables {
  842. indexes, _ := session.ListTableIndexes(table)
  843. for _, index := range indexes {
  844. columns := make([]string, len(index.Columns))
  845. for i, column := range index.Columns {
  846. columns[i] = column.Name
  847. }
  848. unique := ""
  849. if index.Unique {
  850. unique = "UNIQUE "
  851. }
  852. rows = append(rows, map[string]interface{}{
  853. "schemaname": "public", "tablename": table, "indexname": index.Name, "tablespace": nil,
  854. "indexdef": fmt.Sprintf("CREATE %sINDEX %s ON %s (%s)", unique, index.Name, table, strings.Join(columns, ", ")),
  855. })
  856. }
  857. }
  858. }
  859. for _, match := range catalogFilterPattern.FindAllStringSubmatch(sql, -1) {
  860. column, expected := strings.ToLower(match[1]), strings.ReplaceAll(match[2], "''", "'")
  861. filtered := rows[:0]
  862. for _, row := range rows {
  863. if value, ok := row[column]; ok && strings.EqualFold(fmt.Sprintf("%v", value), expected) {
  864. filtered = append(filtered, row)
  865. }
  866. }
  867. rows = filtered
  868. }
  869. columns := catalogProjection(sql, rows)
  870. result := executor.NewResult("SELECT")
  871. if len(columns) == 1 && columns[0] == "count(*)" {
  872. result.AddColumnWithType("count", "INTEGER")
  873. result.AddRow(int64(len(rows)))
  874. return result, true, nil
  875. }
  876. for _, column := range columns {
  877. columnType := "TEXT"
  878. if column == "ordinal_position" {
  879. columnType = "INTEGER"
  880. } else if strings.HasPrefix(column, "has") || column == "rowsecurity" {
  881. columnType = "BOOLEAN"
  882. }
  883. result.AddColumnWithType(column, columnType)
  884. }
  885. for _, row := range rows {
  886. values := make([]interface{}, len(columns))
  887. for i, column := range columns {
  888. values[i] = row[column]
  889. }
  890. result.AddRow(values...)
  891. }
  892. return result, true, nil
  893. }
  894. // isRollbackStatement reports whether sql parses as a single ROLLBACK
  895. // statement, including ROLLBACK TO SAVEPOINT.
  896. func isRollbackStatement(sql string) bool {
  897. stmt, err := parser.New(lexer.New(sql)).Parse()
  898. if err != nil {
  899. return false
  900. }
  901. _, ok := stmt.(*parser.RollbackStmt)
  902. return ok
  903. }
  904. func catalogProjection(sql string, rows []map[string]interface{}) []string {
  905. upper := strings.ToUpper(sql)
  906. selectPos, fromPos := strings.Index(upper, "SELECT"), strings.Index(upper, " FROM ")
  907. if selectPos < 0 || fromPos < 0 || fromPos <= selectPos+6 {
  908. return nil
  909. }
  910. projection := strings.TrimSpace(sql[selectPos+6 : fromPos])
  911. projection = strings.TrimSpace(strings.TrimPrefix(strings.ToUpper(projection), "DISTINCT "))
  912. if projection == "*" && len(rows) > 0 {
  913. columns := make([]string, 0, len(rows[0]))
  914. for column := range rows[0] {
  915. columns = append(columns, column)
  916. }
  917. sort.Strings(columns)
  918. return columns
  919. }
  920. parts := strings.Split(projection, ",")
  921. columns := make([]string, 0, len(parts))
  922. for _, part := range parts {
  923. column := strings.TrimSpace(part)
  924. if index := strings.Index(strings.ToUpper(column), " AS "); index >= 0 {
  925. column = strings.TrimSpace(column[:index])
  926. }
  927. if index := strings.LastIndex(column, "."); index >= 0 {
  928. column = column[index+1:]
  929. }
  930. columns = append(columns, strings.ToLower(strings.Trim(column, `"`)))
  931. }
  932. return columns
  933. }
  934. func yesNo(value bool) string {
  935. if value {
  936. return "YES"
  937. }
  938. return "NO"
  939. }
  940. func (c *Connection) sendTabularResult(result *executor.Result, tag string, bindFormats []int16) error {
  941. formats, err := c.resolveResultFormats(bindFormats, result.ColumnTypes, len(result.Columns))
  942. if err != nil {
  943. return c.failResultFormat(err)
  944. }
  945. oids := c.resultColumnOIDs(result.ColumnTypes, len(result.Columns))
  946. if err := c.sendRowDescriptionFormats(result.Columns, result.ColumnTypes, oids, formats); err != nil {
  947. return err
  948. }
  949. for _, row := range result.Rows {
  950. if err := c.sendDataRowFormats(row, oids, formats); err != nil {
  951. return c.failBinaryEncode(err)
  952. }
  953. }
  954. return c.sendCommandComplete(fmt.Sprintf("%s %d", tag, len(result.Rows)))
  955. }
  956. func (c *Connection) handleClose(msg *Message) error {
  957. if c.extendedFailed {
  958. return nil
  959. }
  960. if len(msg.Data) < 2 {
  961. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Close message"))
  962. }
  963. name, pos, err := readCString(msg.Data, 1)
  964. if err != nil || pos != len(msg.Data) {
  965. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Close name"))
  966. }
  967. if msg.Data[0] == 'S' {
  968. delete(c.statements, name)
  969. } else if msg.Data[0] == 'P' {
  970. delete(c.portals, name)
  971. } else {
  972. return c.failExtended(ErrCodeProtocolViolation, fmt.Errorf("invalid Close target"))
  973. }
  974. return c.writeMessage(MsgCloseComplete, nil)
  975. }
  976. func (c *Connection) failExtended(code string, err error) error {
  977. c.extendedFailed = true
  978. if c.txStatus == TxStatusInBlock {
  979. c.txStatus = TxStatusFailed
  980. }
  981. return c.sendError("ERROR", code, err.Error())
  982. }
  983. func (c *Connection) handleProxyError(msg *Message) error {
  984. if len(msg.Data) != 1 || (msg.Data[0] != MsgQuery && msg.Data[0] != MsgParse) {
  985. _ = c.sendError("FATAL", ErrCodeProtocolViolation, "invalid proxy error relay")
  986. return io.EOF
  987. }
  988. code, message := "42501", "permission denied by API key scopes"
  989. if c.txStatus == TxStatusFailed {
  990. code, message = ErrCodeTransactionAborted, "current transaction is aborted, commands ignored until end of transaction block"
  991. }
  992. if msg.Data[0] == MsgParse {
  993. c.extendedCycle = true
  994. return c.failExtended(code, errors.New(message))
  995. }
  996. if c.txStatus == TxStatusInBlock {
  997. c.txStatus = TxStatusFailed
  998. }
  999. if err := c.sendError("ERROR", code, message); err != nil {
  1000. return err
  1001. }
  1002. return c.sendReadyForQuery()
  1003. }
  1004. // analysisTypeMismatch reports whether the error is an analyzer type-mismatch,
  1005. // which is reported with SQLSTATE 42804 instead of a generic internal error.
  1006. func analysisTypeMismatch(err error) bool {
  1007. var analysisErr *analyzer.AnalysisError
  1008. return errors.As(err, &analysisErr) && analysisErr.Type == analyzer.ErrTypeMismatch
  1009. }
  1010. type boundParameter struct {
  1011. value []byte
  1012. oid int32
  1013. format int16
  1014. null bool
  1015. }
  1016. func readCString(data []byte, pos int) (string, int, error) {
  1017. if pos < 0 || pos >= len(data) {
  1018. return "", pos, fmt.Errorf("missing null-terminated string")
  1019. }
  1020. end := bytes.IndexByte(data[pos:], 0)
  1021. if end < 0 {
  1022. return "", pos, fmt.Errorf("unterminated string")
  1023. }
  1024. return string(data[pos : pos+end]), pos + end + 1, nil
  1025. }
  1026. func readInt16List(data []byte, pos int) ([]int16, int, error) {
  1027. if pos+2 > len(data) {
  1028. return nil, pos, fmt.Errorf("missing list length")
  1029. }
  1030. count := int(binary.BigEndian.Uint16(data[pos : pos+2]))
  1031. pos += 2
  1032. if pos+count*2 > len(data) {
  1033. return nil, pos, fmt.Errorf("truncated list")
  1034. }
  1035. result := make([]int16, count)
  1036. for i := range result {
  1037. result[i] = int16(binary.BigEndian.Uint16(data[pos : pos+2]))
  1038. pos += 2
  1039. }
  1040. return result, pos, nil
  1041. }
  1042. func parameterOID(oids []int32, index int) int32 {
  1043. if index < len(oids) {
  1044. return oids[index]
  1045. }
  1046. return 0
  1047. }
  1048. func parameterFormat(formats []int16, index int) int16 {
  1049. if len(formats) == 1 {
  1050. return formats[0]
  1051. }
  1052. if index < len(formats) {
  1053. return formats[index]
  1054. }
  1055. return 0
  1056. }
  1057. func bindQuery(query string, params []boundParameter) (string, error) {
  1058. var result strings.Builder
  1059. last := 0
  1060. for _, reference := range scanParameters(query) {
  1061. result.WriteString(query[last:reference.start])
  1062. if reference.number < 1 || reference.number > len(params) {
  1063. return "", fmt.Errorf("parameter %s was not provided", query[reference.start:reference.end])
  1064. }
  1065. literal, err := parameterLiteral(params[reference.number-1])
  1066. if err != nil {
  1067. return "", fmt.Errorf("parameter $%d: %w", reference.number, err)
  1068. }
  1069. result.WriteString(literal)
  1070. last = reference.end
  1071. }
  1072. result.WriteString(query[last:])
  1073. return result.String(), nil
  1074. }
  1075. func parameterLiteral(param boundParameter) (string, error) {
  1076. if param.null {
  1077. return "NULL", nil
  1078. }
  1079. if param.format == 1 {
  1080. if element, isArray := arrayParamElementType(param.oid); isArray {
  1081. return binaryArrayLiteral(element, param.value)
  1082. }
  1083. if param.oid == 3802 {
  1084. // PostgreSQL's binary jsonb format is a version byte followed by the
  1085. // document text. pgx sends this form by default.
  1086. if len(param.value) == 0 {
  1087. return "", pgerror.InvalidText("jsonb binary parameter is empty")
  1088. }
  1089. if param.value[0] != 1 {
  1090. return "", pgerror.InvalidText("unsupported jsonb binary format version %d", param.value[0])
  1091. }
  1092. canonical, err := executor.CanonicalizeJSONB(string(param.value[1:]))
  1093. if err != nil {
  1094. return "", err
  1095. }
  1096. return "'" + strings.ReplaceAll(canonical, "'", "''") + "'::jsonb", nil
  1097. }
  1098. switch param.oid {
  1099. case 700, 701:
  1100. return binaryFloatText(param.oid, param.value)
  1101. case 1700:
  1102. return binaryNumericText(param.value)
  1103. case 16:
  1104. if len(param.value) != 1 || param.value[0] > 1 {
  1105. return "", pgerror.InvalidText("invalid binary boolean parameter")
  1106. }
  1107. if param.value[0] == 0 {
  1108. return "FALSE", nil
  1109. }
  1110. return "TRUE", nil
  1111. case 21:
  1112. if len(param.value) != 2 {
  1113. return "", fmt.Errorf("invalid binary int2")
  1114. }
  1115. return strconv.FormatInt(int64(int16(binary.BigEndian.Uint16(param.value))), 10), nil
  1116. case 23:
  1117. if len(param.value) != 4 {
  1118. return "", fmt.Errorf("invalid binary int4")
  1119. }
  1120. return strconv.FormatInt(int64(int32(binary.BigEndian.Uint32(param.value))), 10), nil
  1121. case 20:
  1122. if len(param.value) != 8 {
  1123. return "", fmt.Errorf("invalid binary int8")
  1124. }
  1125. return strconv.FormatInt(int64(binary.BigEndian.Uint64(param.value)), 10), nil
  1126. default:
  1127. return "", fmt.Errorf("%w: binary parameter format for OID %d", pgerror.ErrFeatureNotSupported, param.oid)
  1128. }
  1129. }
  1130. value := string(param.value)
  1131. if param.oid == 3802 {
  1132. // A text-format jsonb parameter is canonicalized at Bind, so the executor
  1133. // receives the same bytes a jsonb column stores and an invalid document
  1134. // fails before execution.
  1135. canonical, err := executor.CanonicalizeJSONB(value)
  1136. if err != nil {
  1137. return "", err
  1138. }
  1139. return "'" + strings.ReplaceAll(canonical, "'", "''") + "'::jsonb", nil
  1140. }
  1141. if element, isArray := arrayParamElementType(param.oid); isArray {
  1142. // The bound value is PostgreSQL array text. Validate and canonicalize it
  1143. // now so a malformed array fails at Bind instead of during row
  1144. // evaluation, then emit a typed literal the executor accepts unchanged.
  1145. arrayType := element + "[]"
  1146. canonical, err := executor.CanonicalizeArrayText(value, arrayType)
  1147. if err != nil {
  1148. return "", err
  1149. }
  1150. return "'" + strings.ReplaceAll(canonical, "'", "''") + "'::" + arrayType, nil
  1151. }
  1152. switch param.oid {
  1153. case 0:
  1154. if strings.EqualFold(value, "true") || strings.EqualFold(value, "false") {
  1155. return strings.ToUpper(value), nil
  1156. }
  1157. if _, err := strconv.ParseFloat(value, 64); err == nil && value != "" {
  1158. return value, nil
  1159. }
  1160. return "'" + strings.ReplaceAll(value, "'", "''") + "'", nil
  1161. case 16:
  1162. if strings.EqualFold(value, "true") || value == "1" || value == "t" {
  1163. return "TRUE", nil
  1164. }
  1165. return "FALSE", nil
  1166. case 20, 21, 23, 26, 700, 701, 1700:
  1167. if _, err := strconv.ParseFloat(value, 64); err != nil {
  1168. return "", fmt.Errorf("invalid numeric value")
  1169. }
  1170. return value, nil
  1171. default:
  1172. return "'" + strings.ReplaceAll(value, "'", "''") + "'", nil
  1173. }
  1174. }
  1175. // sendResult sends a statement's result. columnTypes are the types reported in
  1176. // RowDescription (already corrected for BLOB values) and formats are the
  1177. // portal's resolved per-column format codes, or nil for all-text results.
  1178. func (c *Connection) sendResult(result *executor.Result, stmt parser.Statement, columnTypes []string, formats []int16) error {
  1179. // Any statement that produced a row set (SELECT, or INSERT/UPDATE/DELETE
  1180. // with RETURNING) sends a row description and its data rows. Other
  1181. // statements only send the command completion tag.
  1182. if len(result.Columns) > 0 {
  1183. oids := c.resultColumnOIDs(columnTypes, len(result.Columns))
  1184. if err := c.sendRowDescriptionFormats(result.Columns, columnTypes, oids, formats); err != nil {
  1185. return err
  1186. }
  1187. for _, row := range result.Rows {
  1188. if err := c.sendDataRowFormats(row, oids, formats); err != nil {
  1189. return c.failBinaryEncode(err)
  1190. }
  1191. }
  1192. return c.sendCommandComplete(c.getCommandTag(stmt, result))
  1193. }
  1194. // For other statements, just send command complete
  1195. tag := c.getCommandTag(stmt, result)
  1196. return c.sendCommandComplete(tag)
  1197. }
  1198. // wireColumnTypes corrects declared-affinity metadata when SQLite has stored a
  1199. // value of another type. In particular, binding []byte to a VARCHAR column is
  1200. // still a BLOB in SQLite; advertising TEXT while encoding PostgreSQL bytea text
  1201. // would make clients receive the literal "\\x..." instead of the original
  1202. // bytes.
  1203. func wireColumnTypes(result *executor.Result) []string {
  1204. types := append([]string(nil), result.ColumnTypes...)
  1205. if len(types) < len(result.Columns) {
  1206. types = append(types, make([]string, len(result.Columns)-len(types))...)
  1207. }
  1208. for _, row := range result.Rows {
  1209. for i, value := range row {
  1210. if i >= len(types) {
  1211. break
  1212. }
  1213. if _, ok := value.([]byte); ok {
  1214. types[i] = "BLOB"
  1215. }
  1216. }
  1217. }
  1218. return types
  1219. }
  1220. // getCommandTag returns the command completion tag
  1221. func (c *Connection) getCommandTag(stmt parser.Statement, result *executor.Result) string {
  1222. switch s := stmt.(type) {
  1223. case *parser.SelectStmt:
  1224. return fmt.Sprintf("SELECT %d", len(result.Rows))
  1225. case *parser.CreateTableStmt:
  1226. return "CREATE TABLE"
  1227. case *parser.DropTableStmt:
  1228. return "DROP TABLE"
  1229. case *parser.CreateIndexStmt:
  1230. return "CREATE INDEX"
  1231. case *parser.DropIndexStmt:
  1232. return "DROP INDEX"
  1233. case *parser.AlterTableStmt:
  1234. return "ALTER TABLE"
  1235. case *parser.InsertStmt:
  1236. return fmt.Sprintf("INSERT 0 %d", result.RowsAffected)
  1237. case *parser.UpdateStmt:
  1238. return fmt.Sprintf("UPDATE %d", result.RowsAffected)
  1239. case *parser.DeleteStmt:
  1240. return fmt.Sprintf("DELETE %d", result.RowsAffected)
  1241. case *parser.BeginStmt:
  1242. c.txStatus = TxStatusInBlock
  1243. return "BEGIN"
  1244. case *parser.CommitStmt:
  1245. c.txStatus = TxStatusIdle
  1246. return "COMMIT"
  1247. case *parser.RollbackStmt:
  1248. if s.Savepoint != "" {
  1249. c.txStatus = TxStatusInBlock
  1250. return "ROLLBACK"
  1251. }
  1252. c.txStatus = TxStatusIdle
  1253. return "ROLLBACK"
  1254. case *parser.SavepointStmt:
  1255. c.txStatus = TxStatusInBlock
  1256. return "SAVEPOINT"
  1257. case *parser.ReleaseStmt:
  1258. c.txStatus = TxStatusInBlock
  1259. return "RELEASE"
  1260. case *parser.ListenStmt:
  1261. return "LISTEN"
  1262. case *parser.UnlistenStmt:
  1263. return "UNLISTEN"
  1264. case *parser.NotifyStmt:
  1265. return "NOTIFY"
  1266. default:
  1267. return "OK"
  1268. }
  1269. }
  1270. // sendAuthenticationOk sends authentication OK message
  1271. func (c *Connection) sendAuthenticationOk() error {
  1272. mb := NewMessageBuilder()
  1273. mb.WriteInt32(0) // Auth OK
  1274. return c.writeMessage(MsgAuthenticationOk, mb.Bytes())
  1275. }
  1276. // drainNotifications writes every notification currently buffered for this
  1277. // session. It is called at protocol-safe points (after Sync/ReadyForQuery).
  1278. func (c *Connection) drainNotifications() error {
  1279. ch := c.executor.NotificationChannel()
  1280. for {
  1281. select {
  1282. case n := <-ch:
  1283. if err := c.sendNotification(n); err != nil {
  1284. return err
  1285. }
  1286. default:
  1287. return c.writer.Flush()
  1288. }
  1289. }
  1290. }
  1291. // sendNotification writes a NotificationResponse frame. The frame is only
  1292. // written by the connection's main goroutine, never from a publisher.
  1293. func (c *Connection) sendNotification(n storage.Notification) error {
  1294. mb := NewMessageBuilder()
  1295. mb.WriteInt32(n.PID)
  1296. mb.WriteString(n.Channel)
  1297. mb.WriteString(n.Payload)
  1298. return c.writeMessage(MsgNotificationResponse, mb.Bytes())
  1299. }
  1300. // sendLSN exposes the last commit LSN as a ParameterStatus. Drivers that do
  1301. // not know the key ignore it; subscribers can use it as an ordering cursor.
  1302. func (c *Connection) sendLSN(lsn uint64) error {
  1303. return c.sendParameterStatus("pizzasql.lsn", strconv.FormatUint(lsn, 10))
  1304. }
  1305. // sendParameterStatus sends a parameter status message
  1306. func (c *Connection) sendParameterStatus(name, value string) error {
  1307. mb := NewMessageBuilder()
  1308. mb.WriteString(name)
  1309. mb.WriteString(value)
  1310. return c.writeMessage(MsgParameterStatus, mb.Bytes())
  1311. }
  1312. // sendBackendKeyData sends backend key data
  1313. func (c *Connection) sendBackendKeyData(processID, secretKey int32) error {
  1314. mb := NewMessageBuilder()
  1315. mb.WriteInt32(processID)
  1316. mb.WriteInt32(secretKey)
  1317. return c.writeMessage(MsgBackendKeyData, mb.Bytes())
  1318. }
  1319. // isIdleRollback reports whether a bare ROLLBACK found no transaction to roll
  1320. // back. A COMMIT rejected by storage has already ended the transaction, so the
  1321. // client's cleanup ROLLBACK must complete (PostgreSQL reports a warning and
  1322. // succeeds) instead of surfacing an internal error on an idle session.
  1323. func isIdleRollback(stmt parser.Statement, status byte, err error) bool {
  1324. rollback, ok := stmt.(*parser.RollbackStmt)
  1325. if !ok || rollback.Savepoint != "" {
  1326. return false
  1327. }
  1328. return status == TxStatusIdle && errors.Is(err, executor.ErrNoTransaction)
  1329. }
  1330. // sendReadyForQuery sends ready for query message
  1331. func (c *Connection) sendReadyForQuery() error {
  1332. mb := NewMessageBuilder()
  1333. mb.AppendByte(c.txStatus)
  1334. if err := c.writeMessage(MsgReadyForQuery, mb.Bytes()); err != nil {
  1335. return err
  1336. }
  1337. // ReadyForQuery closes out a response cycle, so flush everything buffered
  1338. // so far. This is what makes simple-query results and Sync responses
  1339. // visible to the client.
  1340. return c.writer.Flush()
  1341. }
  1342. // sendEmptyQueryResponse sends empty query response
  1343. func (c *Connection) sendEmptyQueryResponse() error {
  1344. return c.writeMessage(MsgEmptyQueryResponse, []byte{})
  1345. }
  1346. // sendParameterDescription reports the negotiated parameter types of a
  1347. // prepared statement. The protocol count field is 16-bit and the negotiated
  1348. // list never exceeds maxParameterNumber, so the conversion cannot lose a count.
  1349. func (c *Connection) sendParameterDescription(oids []int32) error {
  1350. if len(oids) > maxParameterNumber {
  1351. return fmt.Errorf("parameter description has %d entries; the protocol limit is %d", len(oids), maxParameterNumber)
  1352. }
  1353. mb := NewMessageBuilder()
  1354. mb.WriteInt16(int16(uint16(len(oids))))
  1355. for _, oid := range oids {
  1356. mb.WriteInt32(oid)
  1357. }
  1358. return c.writeMessage(MsgParameterDescription, mb.Bytes())
  1359. }
  1360. // sendRowDescription sends row description (column metadata) in text format.
  1361. func (c *Connection) sendRowDescription(columns []string, columnTypes []string) error {
  1362. return c.sendRowDescriptionFormats(columns, columnTypes, c.resultColumnOIDs(columnTypes, len(columns)), nil)
  1363. }
  1364. // sendRowDescriptionFormats sends row description with the per-column formats a
  1365. // portal resolved at Bind. PostgreSQL reports the bound formats in a portal
  1366. // RowDescription; this server emits its RowDescription at Execute instead of
  1367. // Describe, so the portal's formats travel with the row metadata. OIDs are the
  1368. // same for text and binary results.
  1369. func (c *Connection) sendRowDescriptionFormats(columns []string, columnTypes []string, oids []int32, formats []int16) error {
  1370. mb := NewMessageBuilder()
  1371. mb.WriteInt16(int16(len(columns)))
  1372. for i, col := range columns {
  1373. colType := typeNameAt(columnTypes, i)
  1374. format := int16(0)
  1375. if i < len(formats) {
  1376. format = formats[i]
  1377. }
  1378. mb.WriteString(col)
  1379. mb.WriteInt32(0) // table OID
  1380. mb.WriteInt16(0) // column attribute number
  1381. mb.WriteInt32(oids[i]) // type OID
  1382. mb.WriteInt16(c.getTypeSizeForType(colType)) // type size
  1383. mb.WriteInt32(-1) // type modifier
  1384. mb.WriteInt16(format) // format code
  1385. }
  1386. return c.writeMessage(MsgRowDescription, mb.Bytes())
  1387. }
  1388. // resultColumnOIDs returns the PostgreSQL OID reported for every result column.
  1389. func (c *Connection) resultColumnOIDs(columnTypes []string, columnCount int) []int32 {
  1390. oids := make([]int32, columnCount)
  1391. for i := range oids {
  1392. oids[i] = c.getOIDForType(typeNameAt(columnTypes, i))
  1393. }
  1394. return oids
  1395. }
  1396. // sendDataRow sends a data row in text format
  1397. func (c *Connection) sendDataRow(row []interface{}, columns []string) error {
  1398. return c.sendDataRowFormats(row, nil, nil)
  1399. }
  1400. // sendDataRowFormats sends one DataRow, choosing text or binary encoding per
  1401. // column from formats. NULL is always length -1. Binary values are appended
  1402. // directly into the DataRow buffer; a value that cannot be encoded fails before
  1403. // the row is written, so the client never receives a partial DataRow.
  1404. func (c *Connection) sendDataRowFormats(row []interface{}, oids []int32, formats []int16) error {
  1405. mb := NewMessageBuilder()
  1406. mb.WriteInt16(int16(len(row)))
  1407. for i, value := range row {
  1408. if value == nil {
  1409. mb.WriteInt32(-1) // NULL indicator
  1410. continue
  1411. }
  1412. format := int16(0)
  1413. if i < len(formats) {
  1414. format = formats[i]
  1415. }
  1416. if format == 0 {
  1417. strValue := c.valueToString(value)
  1418. mb.WriteInt32(int32(len(strValue)))
  1419. mb.WriteBytes([]byte(strValue))
  1420. continue
  1421. }
  1422. oid := int32(25) // TEXT, the fallback RowDescription OID
  1423. if i < len(oids) {
  1424. oid = oids[i]
  1425. }
  1426. err := mb.AppendBinary(func(dst []byte) ([]byte, error) {
  1427. return appendBinaryResultValue(dst, oid, value)
  1428. })
  1429. if err != nil {
  1430. return fmt.Errorf("binary result column %d: %w", i+1, err)
  1431. }
  1432. }
  1433. return c.writeMessage(MsgDataRow, mb.Bytes())
  1434. }
  1435. // sendCommandComplete sends command complete message
  1436. func (c *Connection) sendCommandComplete(tag string) error {
  1437. mb := NewMessageBuilder()
  1438. mb.WriteString(tag)
  1439. return c.writeMessage(MsgCommandComplete, mb.Bytes())
  1440. }
  1441. // sendError sends an error response
  1442. func (c *Connection) sendError(severity, code, message string) error {
  1443. if severity == "ERROR" && c.txStatus == TxStatusInBlock {
  1444. c.txStatus = TxStatusFailed
  1445. }
  1446. mb := NewMessageBuilder()
  1447. mb.AppendByte(ErrorFieldSeverity)
  1448. mb.WriteString(severity)
  1449. mb.AppendByte(ErrorFieldCode)
  1450. mb.WriteString(code)
  1451. mb.AppendByte(ErrorFieldMessage)
  1452. mb.WriteString(message)
  1453. mb.AppendByte(0) // Terminator
  1454. if err := c.writeMessage(MsgErrorResponse, mb.Bytes()); err != nil {
  1455. return err
  1456. }
  1457. // Errors must be visible promptly, including FATAL startup failures that
  1458. // are not followed by a ReadyForQuery before the connection closes.
  1459. return c.writer.Flush()
  1460. }
  1461. // writeMessage buffers a message for the connection. It does not flush, so
  1462. // callers that need to make a response visible to the client must flush at the
  1463. // appropriate protocol boundary (ReadyForQuery, an explicit Flush message, or
  1464. // an error response). Buffering amortizes the per-message syscalls that a
  1465. // result set would otherwise incur; the underlying bufio.Writer bounds memory
  1466. // use so large result sets cannot grow the buffer without limit.
  1467. func (c *Connection) writeMessage(msgType byte, data []byte) error {
  1468. if !c.quiet {
  1469. log.Printf("Sending message type=%c length=%d", msgType, len(data)+4)
  1470. }
  1471. return WriteMessage(c.writer, msgType, data)
  1472. }
  1473. // arrayElementTypeName reports the element type of an array type name such as
  1474. // "INTEGER[]". It reports false for scalar type names.
  1475. func arrayElementTypeName(typeName string) (string, bool) {
  1476. upper := strings.ToUpper(strings.TrimSpace(typeName))
  1477. if !strings.HasSuffix(upper, "[]") {
  1478. return "", false
  1479. }
  1480. return strings.TrimSpace(strings.TrimSuffix(upper, "[]")), true
  1481. }
  1482. // arrayOIDForElement maps an array element type name to its PostgreSQL array
  1483. // OID. Narrower integer types report int8[] because values are not
  1484. // range-checked, matching the scalar carrier rule; NUMERIC reports numeric[]
  1485. // because array elements stay text.
  1486. func arrayOIDForElement(element string) int32 {
  1487. base := strings.ToUpper(strings.TrimSpace(element))
  1488. if idx := strings.IndexByte(base, '('); idx >= 0 {
  1489. base = strings.TrimSpace(base[:idx])
  1490. }
  1491. switch base {
  1492. case "INTEGER", "INT", "INT4":
  1493. return 1007 // INT4ARRAYOID
  1494. case "BIGINT", "INT8", "SMALLINT", "INT2", "TINYINT", "MEDIUMINT":
  1495. return 1016 // INT8ARRAYOID
  1496. case "BOOLEAN", "BOOL":
  1497. return 1000 // BOOLARRAYOID
  1498. case "REAL", "FLOAT", "FLOAT4":
  1499. return 1021 // FLOAT4ARRAYOID
  1500. case "DOUBLE", "DOUBLE PRECISION", "FLOAT8":
  1501. return 1022 // FLOAT8ARRAYOID
  1502. case "NUMERIC", "DECIMAL":
  1503. return 1231 // NUMERICARRAYOID
  1504. case "VARCHAR", "NVARCHAR", "CHARACTER VARYING":
  1505. return 1015 // VARCHARARRAYOID
  1506. default:
  1507. return 1009 // TEXTARRAYOID
  1508. }
  1509. }
  1510. // arrayParamElementType maps an array parameter OID to the element type the
  1511. // bound literal is cast to. Unknown OIDs are handled by callers.
  1512. func arrayParamElementType(oid int32) (string, bool) {
  1513. switch oid {
  1514. case 1009:
  1515. return "TEXT", true
  1516. case 1015:
  1517. return "VARCHAR", true
  1518. case 1007:
  1519. return "INTEGER", true
  1520. case 1016:
  1521. return "BIGINT", true
  1522. case 1005:
  1523. return "SMALLINT", true
  1524. case 1000:
  1525. return "BOOLEAN", true
  1526. case 1021:
  1527. return "REAL", true
  1528. case 1022:
  1529. return "DOUBLE", true
  1530. case 1231:
  1531. return "NUMERIC", true
  1532. default:
  1533. return "", false
  1534. }
  1535. }
  1536. // getOIDForType returns PostgreSQL OID for type.
  1537. //
  1538. // Types narrower than the value the engine carries are reported as the carrier
  1539. // type, because the engine does not range-check stored or cast values: a value
  1540. // that does not fit int2/int4 or float4 would fail client-side decoding rather
  1541. // than having been rejected on write. INTEGER and REAL keep their declared
  1542. // mappings, which predate this rule and are what existing clients expect.
  1543. func (c *Connection) getOIDForType(typeName string) int32 {
  1544. if element, ok := arrayElementTypeName(typeName); ok {
  1545. return arrayOIDForElement(element)
  1546. }
  1547. switch strings.ToUpper(typeName) {
  1548. case "SMALLINT", "INT2", "TINYINT", "MEDIUMINT":
  1549. // Carried as int64 and not range-checked, so int8 is the honest type.
  1550. return 20 // INT8OID
  1551. case "INTEGER", "INT", "INT4":
  1552. return 23 // INT4OID
  1553. case "BIGINT", "INT8":
  1554. return 20 // INT8OID
  1555. case "NUMERIC", "DECIMAL":
  1556. // Values round-trip through JSON as float64; there is no exact decimal
  1557. // carrier, so NUMERIC is not advertised.
  1558. return 701 // FLOAT8OID
  1559. case "JSONB":
  1560. return 3802 // JSONBOID
  1561. case "TEXT", "VARCHAR", "CHAR", "UUID":
  1562. // UUID is stored as text (SQLite-style), so it reports TEXTOID rather
  1563. // than the native PG UUID OID.
  1564. return 25 // TEXTOID
  1565. case "REAL", "FLOAT":
  1566. return 700 // FLOAT4OID
  1567. case "DOUBLE":
  1568. return 701 // FLOAT8OID
  1569. case "BOOLEAN", "BOOL":
  1570. return 16 // BOOLOID
  1571. case "BLOB":
  1572. return 17 // BYTEAOID
  1573. case "DATETIME", "TIMESTAMP":
  1574. // Datetime values are exchanged as UTC RFC3339 (ISO8601 with a timezone
  1575. // offset), which timestamptz decodes directly.
  1576. return 1184 // TIMESTAMPTZOID
  1577. case "DATE":
  1578. return 1082 // DATEOID
  1579. default:
  1580. return 25 // Default to TEXT
  1581. }
  1582. }
  1583. // getTypeSizeForType returns type size in bytes, or -1 for variable length.
  1584. func (c *Connection) getTypeSizeForType(typeName string) int16 {
  1585. if _, ok := arrayElementTypeName(typeName); ok {
  1586. return -1 // arrays are variable length
  1587. }
  1588. switch strings.ToUpper(typeName) {
  1589. case "SMALLINT", "INT2", "TINYINT", "MEDIUMINT":
  1590. return 8 // Reported as int8; see getOIDForType.
  1591. case "INTEGER", "INT", "INT4":
  1592. return 4
  1593. case "BIGINT", "INT8":
  1594. return 8
  1595. case "NUMERIC", "DECIMAL":
  1596. return 8 // Reported as float8; see getOIDForType.
  1597. case "REAL", "FLOAT":
  1598. return 4
  1599. case "DOUBLE":
  1600. return 8
  1601. case "BOOLEAN", "BOOL":
  1602. return 1
  1603. case "DATETIME", "TIMESTAMP":
  1604. return 8
  1605. case "DATE":
  1606. return 4
  1607. default:
  1608. return -1 // Variable length
  1609. }
  1610. }
  1611. // valueToString converts a value to its PostgreSQL text representation
  1612. func (c *Connection) valueToString(value interface{}) string {
  1613. return textValueString(value)
  1614. }
  1615. // textValueString is the text representation the wire layer sends for a value.
  1616. // Binary text and bytea results reuse it so both formats carry the same bytes
  1617. // for values without a native binary form. PostgreSQL's text format for bytea is
  1618. // \x followed by hex, which lets libpq/pgx decode a BLOB column (OID 17)
  1619. // losslessly.
  1620. func textValueString(value interface{}) string {
  1621. if value == nil {
  1622. return ""
  1623. }
  1624. if b, ok := value.([]byte); ok {
  1625. return `\x` + hex.EncodeToString(b)
  1626. }
  1627. return fmt.Sprintf("%v", value)
  1628. }
  1629. // handleVersionQuery handles SELECT version()
  1630. func (c *Connection) handleVersionQuery() error {
  1631. columns := []string{"version"}
  1632. columnTypes := []string{"TEXT"}
  1633. if err := c.sendRowDescription(columns, columnTypes); err != nil {
  1634. return err
  1635. }
  1636. row := []interface{}{"PostgreSQL " + version.PostgreSQLCompatVersion + " (PizzaSQL)"}
  1637. if err := c.sendDataRow(row, columns); err != nil {
  1638. return err
  1639. }
  1640. if err := c.sendCommandComplete("SELECT 1"); err != nil {
  1641. return err
  1642. }
  1643. return c.sendReadyForQuery()
  1644. }
  1645. // handleCurrentUserQuery handles SELECT current_user
  1646. func (c *Connection) handleCurrentUserQuery() error {
  1647. columns := []string{"current_user"}
  1648. columnTypes := []string{"TEXT"}
  1649. if err := c.sendRowDescription(columns, columnTypes); err != nil {
  1650. return err
  1651. }
  1652. user := c.params["user"]
  1653. if user == "" {
  1654. user = "pizzasql"
  1655. }
  1656. row := []interface{}{user}
  1657. if err := c.sendDataRow(row, columns); err != nil {
  1658. return err
  1659. }
  1660. if err := c.sendCommandComplete("SELECT 1"); err != nil {
  1661. return err
  1662. }
  1663. return c.sendReadyForQuery()
  1664. }
  1665. // handleShowCommand handles SHOW commands
  1666. func (c *Connection) handleShowCommand(sqlUpper string) error {
  1667. var value string
  1668. var name string
  1669. if sqlUpper == "SERVER_VERSION" {
  1670. name = "server_version"
  1671. value = version.PostgreSQLCompatVersion
  1672. } else if sqlUpper == "SERVER_ENCODING" {
  1673. name = "server_encoding"
  1674. value = "UTF8"
  1675. } else if sqlUpper == "CLIENT_ENCODING" {
  1676. name = "client_encoding"
  1677. value = "UTF8"
  1678. } else {
  1679. // Unknown SHOW command
  1680. c.sendError("ERROR", ErrCodeFeatureNotSupported, "SHOW command not supported")
  1681. return c.sendReadyForQuery()
  1682. }
  1683. columns := []string{name}
  1684. columnTypes := []string{"TEXT"}
  1685. if err := c.sendRowDescription(columns, columnTypes); err != nil {
  1686. return err
  1687. }
  1688. row := []interface{}{value}
  1689. if err := c.sendDataRow(row, columns); err != nil {
  1690. return err
  1691. }
  1692. if err := c.sendCommandComplete("SHOW"); err != nil {
  1693. return err
  1694. }
  1695. return c.sendReadyForQuery()
  1696. }