| 44 | } |
| 45 | |
| 46 | export class OracleConnection extends AbstractSqlConnection { |
| 47 | private oraclePool?: oracledb.Pool; |
| 48 | // Resolves `password` callbacks per acquire so `callRoutine` doesn't bypass password rotation. |
| 49 | private acquireOracleConnection?: () => Promise<oracledb.Connection>; |
| 50 | |
| 51 | override async createKyselyDialect(overrides: PoolAttributes): Promise<OracleDialect> { |
| 52 | const options = this.mapOptions(overrides); |
| 53 | const password = options.password as ConnectionConfig['password']; |
| 54 | const onCreateConnection = this.options.onCreateConnection ?? this.config.get('onCreateConnection'); |
| 55 | |
| 56 | const initialPassword = typeof password === 'function' ? await password() : password; |
| 57 | |
| 58 | const poolOptions = { |
| 59 | ...options, |
| 60 | password: initialPassword, |
| 61 | sessionCallback: onCreateConnection as PoolAttributes['sessionCallback'], |
| 62 | }; |
| 63 | |
| 64 | // Retry pool creation for transient Oracle errors (e.g. ORA-01017 under load) |
| 65 | let pool: oracledb.Pool; |
| 66 | const maxRetries = 3; |
| 67 | |
| 68 | for (let attempt = 1; ; attempt++) { |
| 69 | try { |
| 70 | pool = await oracledb.createPool(poolOptions); |
| 71 | this.oraclePool = pool; |
| 72 | break; |
| 73 | /* v8 ignore start: transient Oracle pool-creation errors are not reproducible in tests */ |
| 74 | } catch (e: any) { |
| 75 | if (attempt < maxRetries && (e.errorNum === 1017 || e.errorNum === 12514 || e.errorNum === 12541)) { |
| 76 | await new Promise(resolve => setTimeout(resolve, 250 * attempt)); |
| 77 | continue; |
| 78 | } |
| 79 | |
| 80 | throw e; |
| 81 | } |
| 82 | /* v8 ignore stop */ |
| 83 | } |
| 84 | |
| 85 | const executeOptions: ExecuteOptions = { |
| 86 | fetchTypeHandler: metaData => { |
| 87 | const bigInt = metaData.dbType === oracledb.DB_TYPE_NUMBER && (metaData.precision ?? 0) > 10; |
| 88 | metaData.name = metaData.name.toLowerCase(); |
| 89 | |
| 90 | if (bigInt || metaData.dbType === oracledb.DB_TYPE_CLOB) { |
| 91 | return { |
| 92 | type: oracledb.DB_TYPE_VARCHAR, |
| 93 | }; |
| 94 | } |
| 95 | |
| 96 | if (metaData.dbType === oracledb.DB_TYPE_BLOB) { |
| 97 | return { |
| 98 | type: oracledb.BUFFER, |
| 99 | }; |
| 100 | } |
| 101 | |
| 102 | return undefined; |
| 103 | }, |
nothing calls this directly
no outgoing calls
no test coverage detected