Class: Sqlx::Database::PgConnection

Inherits:
Object
  • Object
show all
Defined in:
runtime/database/postgresql.rb

Overview

One libpq connection plus the session values this adapter answers from. @changes belongs to the connection, not the process: a second session's write must not overwrite the count a caller reads back. lastval() is the connection's own last sequence value, so last_insert_rowid reads it through the same connection the INSERT ran on.

Instance Method Summary collapse

Constructor Details

#initialize(conninfo) ⇒ PgConnection

Returns a new instance of PgConnection.



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'runtime/database/postgresql.rb', line 113

def initialize(conninfo)
  @dbh = Libpq.PQconnectdb(conninfo)
  if Libpq.PQstatus(@dbh) != Libpq::CONNECTION_OK
    msg = Libpq.PQerrorMessage(@dbh)
    Libpq.PQfinish(@dbh)
    raise Sqlx::ConnectionFailed, "Sqlx::Database: PG connect failed: " + msg
  end
  @changes = 0
  @index = -1
  @closed = false
  res = Libpq.PQexec(@dbh, "SET TimeZone TO 'UTC'")
  status = Libpq.PQresultStatus(res)
  message = Libpq.PQresultErrorMessage(res)
  Libpq.PQclear(res)
  if status != Libpq::PGRES_COMMAND_OK
    Libpq.PQfinish(@dbh)
    raise Sqlx::ConnectionFailed, "Sqlx::Database: PG session setup failed: " + message
  end
  now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  @opened_at = now
  @last_used_at = now
end

Instance Method Details

#attach_to_position(index) ⇒ Object

Attach this connection to the pool position index. The pool calls this once when the connection joins @conns; discard reads index to find the position again. A negative position is not in the pool, so reject it here instead of letting the discard lookup miss.



154
155
156
157
158
159
# File 'runtime/database/postgresql.rb', line 154

def attach_to_position(index)
  if !index.is_a?(Integer) || index < 0
    raise ArgumentError, "Sqlx::Database: connection position must be a non-negative Integer, got " + index.inspect
  end
  @index = index
end

#changes ⇒ Object



161
162
163
164
165
166
# File 'runtime/database/postgresql.rb', line 161

def changes
  if @closed
    raise Sqlx::ConnectionFailed, "Sqlx::Database: connection is closed"
  end
  @changes
end

#changes=(value) ⇒ Object



168
169
170
# File 'runtime/database/postgresql.rb', line 168

def changes=(value)
  @changes = value
end

#close ⇒ Object



195
196
197
198
199
# File 'runtime/database/postgresql.rb', line 195

def close
  return if @closed
  Libpq.PQfinish(@dbh)
  @closed = true
end

#dbh ⇒ Object



136
137
138
139
140
141
# File 'runtime/database/postgresql.rb', line 136

def dbh
  if @closed
    raise Sqlx::ConnectionFailed, "Sqlx::Database: connection is closed"
  end
  @dbh
end

#index ⇒ Object

The pool position this connection occupies. The position is stable for the connection's life: a replacement connection opens at the same index, so a lease token never has to be renumbered.



146
147
148
# File 'runtime/database/postgresql.rb', line 146

def index
  @index
end

#mark_used(now) ⇒ Object

Record the pool release time; the next checkout measures idleness from it. The pool calls this when it returns the connection to the free list.



174
175
176
# File 'runtime/database/postgresql.rb', line 174

def mark_used(now)
  @last_used_at = now
end

#usable?(now, idle_timeout_seconds, max_lifetime_seconds) ⇒ Boolean

Whether this connection may be handed to a checkout: inside the idle and lifetime bounds, and alive to a SELECT 1 ping. The ping is driver plumbing, not app SQL, so it is not recorded in the query trace or the request's DB time.

Returns:

  • (Boolean)


182
183
184
185
186
187
188
189
190
191
192
193
# File 'runtime/database/postgresql.rb', line 182

def usable?(now, idle_timeout_seconds, max_lifetime_seconds)
  return false if max_lifetime_seconds > 0 && age_seconds(now) > max_lifetime_seconds
  return false if idle_timeout_seconds > 0 && idle_seconds(now) > idle_timeout_seconds
  return false if Libpq.PQstatus(dbh) != Libpq::CONNECTION_OK

  res = Libpq.PQexec(dbh, "SELECT 1")
  ok = Libpq.PQresultStatus(res) == Libpq::PGRES_TUPLES_OK
  Libpq.PQclear(res)
  ok
rescue Sqlx::ConnectionFailed
  false
end