CancelRequest sends a cancel request to the PostgreSQL server. It returns an error if unable to deliver the cancel request, but lack of an error does not ensure that the query was canceled. As specified in the documentation, there is no way to be sure a query was canceled. See https://www.postgresql
(ctx context.Context)
| 1087 | // is no way to be sure a query was canceled. |
| 1088 | // See https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-CANCELING-REQUESTS |
| 1089 | func (pgConn *PgConn) CancelRequest(ctx context.Context) error { |
| 1090 | // Open a cancellation request to the same server. The address is taken from the net.Conn directly instead of reusing |
| 1091 | // the connection config. This is important in high availability configurations where fallback connections may be |
| 1092 | // specified or DNS may be used to load balance. |
| 1093 | serverAddr := pgConn.conn.RemoteAddr() |
| 1094 | var serverNetwork string |
| 1095 | var serverAddress string |
| 1096 | if serverAddr.Network() == "unix" { |
| 1097 | // for unix sockets, RemoteAddr() calls getpeername() which returns the name the |
| 1098 | // server passed to bind(). For Postgres, this is always a relative path "./.s.PGSQL.5432" |
| 1099 | // so connecting to it will fail. Fall back to the config's value |
| 1100 | serverNetwork, serverAddress = NetworkAddress(pgConn.config.Host, pgConn.config.Port) |
| 1101 | } else { |
| 1102 | serverNetwork, serverAddress = serverAddr.Network(), serverAddr.String() |
| 1103 | } |
| 1104 | cancelConn, err := pgConn.config.DialFunc(ctx, serverNetwork, serverAddress) |
| 1105 | if err != nil { |
| 1106 | // In case of unix sockets, RemoteAddr() returns only the file part of the path. If the |
| 1107 | // first connect failed, try the config. |
| 1108 | if serverAddr.Network() != "unix" { |
| 1109 | return err |
| 1110 | } |
| 1111 | serverNetwork, serverAddr := NetworkAddress(pgConn.config.Host, pgConn.config.Port) |
| 1112 | cancelConn, err = pgConn.config.DialFunc(ctx, serverNetwork, serverAddr) |
| 1113 | if err != nil { |
| 1114 | return err |
| 1115 | } |
| 1116 | } |
| 1117 | defer cancelConn.Close() |
| 1118 | |
| 1119 | if ctx != context.Background() { |
| 1120 | contextWatcher := ctxwatch.NewContextWatcher(&DeadlineContextWatcherHandler{Conn: cancelConn}) |
| 1121 | contextWatcher.Watch(ctx) |
| 1122 | defer contextWatcher.Unwatch() |
| 1123 | } |
| 1124 | |
| 1125 | // If the primary connection is encrypted, encrypt the cancel connection the same way so the |
| 1126 | // backend pid and secret key are not exposed to a passive network observer. This mirrors libpq's |
| 1127 | // PQcancelCreate (PG17+), which reuses the original connection's sslmode/gssencmode for the |
| 1128 | // cancel connection. The legacy unencrypted path is still used when the primary connection is |
| 1129 | // plaintext (e.g. unix sockets or sslmode=disable). |
| 1130 | if pgConn.tlsConfig != nil { |
| 1131 | var tlsCancelConn net.Conn |
| 1132 | if pgConn.config.SSLNegotiation == "direct" { |
| 1133 | tlsCancelConn = tls.Client(cancelConn, pgConn.tlsConfig) |
| 1134 | } else { |
| 1135 | tlsCancelConn, err = startTLS(cancelConn, pgConn.tlsConfig) |
| 1136 | if err != nil { |
| 1137 | return fmt.Errorf("tls error on cancel connection: %w", err) |
| 1138 | } |
| 1139 | } |
| 1140 | cancelConn = tlsCancelConn |
| 1141 | defer cancelConn.Close() |
| 1142 | } |
| 1143 | |
| 1144 | buf := make([]byte, 12+len(pgConn.secretKey)) |
| 1145 | binary.BigEndian.PutUint32(buf[0:4], uint32(len(buf))) |
| 1146 | binary.BigEndian.PutUint32(buf[4:8], 80877102) |