@@ -40,33 +40,47 @@ class Pool extends Adapter
4040
4141 /**
4242 * Answers to the getters that describe the adapter rather than a
43- * connection, by method.
43+ * connection, by pool and method.
4444 *
4545 * Every connection in a pool is built by the same factory, so it is the
4646 * same adapter class on the same DSN, and these answers are the same
4747 * whichever connection gives them. Delegating them checked a connection
4848 * out and replayed the whole handle state onto it to read a constant, and
49- * the hot path asks several per document. Getters that read connection or
50- * handle state (the driver, the connection id, anything that varies with
51- * shared tables or with how a connection was set up) still delegate, and
52- * the one capability with a setter is updated by it.
49+ * the hot path asks several per document. They are kept per pool rather
50+ * than per handle because a handle is usually built for one request,
51+ * while its pool lives as long as the process. Getters that read
52+ * connection or handle state (the driver, the connection id, anything
53+ * that varies with shared tables or with how a connection was set up)
54+ * still delegate.
5355 *
54- * @var array<string, mixed>
56+ * @var \WeakMap<UtopiaPool<covariant Adapter>, array<string, mixed> >
5557 */
56- private array $ capabilities = [] ;
58+ private static \ WeakMap $ capabilities ;
5759
5860 /**
5961 * Attribute support this handle asked for, replayed on every checkout so
60- * each connection runs with the value the memoized getter reports.
62+ * each connection runs with the value the getter reports.
6163 */
6264 private ?bool $ supportForAttributes = null ;
6365
66+ /**
67+ * Attribute support as the adapter reports it to this handle. It is the
68+ * one capability with a setter, so it is kept per handle, not per pool.
69+ */
70+ private ?bool $ reportedSupportForAttributes = null ;
71+
6472 /**
6573 * @param UtopiaPool<covariant Adapter> $pool The pool to use for connections. Must contain instances of Adapter.
6674 */
6775 public function __construct (UtopiaPool $ pool )
6876 {
6977 $ this ->pool = $ pool ;
78+
79+ if (!isset (self ::$ capabilities )) {
80+ /** @var \WeakMap<UtopiaPool<covariant Adapter>, array<string, mixed>> $capabilities */
81+ $ capabilities = new \WeakMap ();
82+ self ::$ capabilities = $ capabilities ;
83+ }
7084 }
7185
7286 /**
@@ -129,11 +143,20 @@ public function delegate(string $method, array $args): mixed
129143 */
130144 protected function capability (string $ method ): mixed
131145 {
132- if (!\array_key_exists ($ method , $ this ->capabilities )) {
133- $ this ->capabilities [$ method ] = $ this ->delegate ($ method , []);
146+ $ answers = self ::$ capabilities [$ this ->pool ] ?? [];
147+
148+ if (\array_key_exists ($ method , $ answers )) {
149+ return $ answers [$ method ];
134150 }
135151
136- return $ this ->capabilities [$ method ];
152+ $ answer = $ this ->delegate ($ method , []);
153+
154+ // The checkout can yield to a coroutine that kept another answer meanwhile
155+ $ answers = self ::$ capabilities [$ this ->pool ] ?? [];
156+ $ answers [$ method ] = $ answer ;
157+ self ::$ capabilities [$ this ->pool ] = $ answers ;
158+
159+ return $ answer ;
137160 }
138161
139162 public function getDriver (): mixed
@@ -287,14 +310,18 @@ public function rollbackTransaction(): bool
287310 */
288311 public function getHostname (): string
289312 {
290- if (!empty ($ this ->capabilities [__FUNCTION__ ])) {
291- return $ this ->capabilities [__FUNCTION__ ];
313+ $ hostname = self ::$ capabilities [$ this ->pool ][__FUNCTION__ ] ?? '' ;
314+
315+ if ($ hostname !== '' ) {
316+ return $ hostname ;
292317 }
293318
294319 $ hostname = $ this ->delegate (__FUNCTION__ , \func_get_args ());
295320
296321 if ($ hostname !== '' ) {
297- $ this ->capabilities [__FUNCTION__ ] = $ hostname ;
322+ $ answers = self ::$ capabilities [$ this ->pool ] ?? [];
323+ $ answers [__FUNCTION__ ] = $ hostname ;
324+ self ::$ capabilities [$ this ->pool ] = $ answers ;
298325 }
299326
300327 return $ hostname ;
@@ -579,7 +606,7 @@ public function getSupportForSchemas(): bool
579606
580607 public function getSupportForAttributes (): bool
581608 {
582- return $ this ->capability (__FUNCTION__ );
609+ return $ this ->reportedSupportForAttributes ??= $ this -> delegate (__FUNCTION__ , \func_get_args () );
583610 }
584611
585612 public function getSupportForSchemaAttributes (): bool
@@ -915,7 +942,7 @@ public function setSupportForAttributes(bool $support): bool
915942 {
916943 $ this ->supportForAttributes = $ support ;
917944
918- return $ this ->capabilities [ ' getSupportForAttributes ' ] = $ this ->delegate (__FUNCTION__ , \func_get_args ());
945+ return $ this ->reportedSupportForAttributes = $ this ->delegate (__FUNCTION__ , \func_get_args ());
919946 }
920947
921948 public function getSupportForIntegerBooleans (): bool
0 commit comments