| 143 | // are gone. There is no way to complete the LUW, and silently carrying on would |
| 144 | // lose the data, so poison the client and take the application down |
| 145 | this.fatal = new Error("PG: COMMIT failed, the changes of the current LUW are lost: " |
| 146 | + (error instanceof Error ? error.message : error), {cause: error}); |
| 147 | } |
| 148 | throw this.fatal ?? error; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | /** a failed COMMIT is not recoverable, every further use of the client must crash |
| 153 | rather than degrade into sy-subrc = 4 */ |
| 154 | private checkFatal(): void { |
| 155 | if (this.fatal !== undefined) { |
| 156 | throw this.fatal; |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | /** postgres aborts the full transaction if a statement fails, so wrap modifying |
| 161 | statements in a savepoint, allowing the LUW to continue after eg. duplicate keys */ |
| 162 | private async modifying(sql: string): Promise<pg.QueryResult<any>> { |
| 163 | await this.beginTransaction(); |
| 164 | |
| 165 | await this.client!.query("SAVEPOINT abap_stmt"); |
| 166 | try { |
| 167 | const res = await this.client!.query(sql); |
| 168 | await this.client!.query("RELEASE SAVEPOINT abap_stmt"); |
| 169 | return res; |
| 170 | } catch (error) { |
| 171 | await this.client!.query("ROLLBACK TO SAVEPOINT abap_stmt; RELEASE SAVEPOINT abap_stmt;"); |
| 172 | throw error; |