MCPcopy Create free account
hub / github.com/mikro-orm/mikro-orm / callRoutine

Method callRoutine

packages/oracledb/src/OracleConnection.ts:229–335  ·  view source on GitHub ↗

* Oracle routines acquire their own pool connection with `autoCommit: true` (refcursor binds * and DML need to resolve in one round-trip), so they cannot share the EM's transaction. Wrapping * a writing routine in `em.transactional(...)` would silently auto-commit its writes. Read-only * fu

(routine: Routine, args: Record<string, unknown> = {}, ctx?: Transaction)

Source from the content-addressed store, hash-verified

227 * functions are allowed through.
228 */
229 override async callRoutine<T>(routine: Routine, args: Record<string, unknown> = {}, ctx?: Transaction): Promise<T> {
230 /* v8 ignore next 3 */
231 if (!this.oraclePool || !this.acquireOracleConnection) {
232 throw new Error('Oracle pool not initialised — call connect() before callRoutine().');
233 }
234
235 if (ctx && !isReadOnlyRoutine(routine)) {
236 throw new Error(
237 `Routine ${routine.name} was invoked inside an EntityManager transaction, but Oracle's callRoutine runs on its own pool connection with autoCommit. Read-only functions are allowed through; for procedures or routines that may write, call em.callRoutine() outside em.transactional(), or mark the routine as 'dataAccess: \\'reads-sql-data\\'' / 'no-sql' if it really is read-only.`,
238 );
239 }
240
241 const name = routine.name.toUpperCase();
242 // Cross-schema needs an `OWNER.NAME` prefix; mirror the schema helper's quoting on both branches.
243 const quotedName = this.platform.quoteIdentifier(name);
244 /* v8 ignore next 3 — cross-schema invocation isn't reachable from the single-user test DB;
245 the qualified DDL path (createRoutine/dropRoutine) is covered by helpers.test.ts. */
246 const qualifiedName = routine.schema
247 ? `${this.platform.quoteIdentifier(routine.schema.toUpperCase())}.${quotedName}`
248 : quotedName;
249 const oracleConn = await this.acquireOracleConnection();
250
251 try {
252 if (routine.type === 'function') {
253 const argList = routine.params.map(p => `:${p.name}`).join(', ');
254 const block = `BEGIN :mo_ret := ${qualifiedName}(${argList}); END;`;
255 const bindings: Dictionary = { mo_ret: oracleReturnBind(this.platform as OraclePlatform, routine) };
256
257 for (const p of routine.params) {
258 bindings[p.name as string] = {
259 dir: oracledb.BIND_IN,
260 val: this.convertRoutineInbound(args[p.name as string], p),
261 };
262 }
263
264 const result = await oracleConn.execute(block, bindings, { autoCommit: true });
265 return this.convertRoutineOutbound<T>((result.outBinds as Dictionary)?.mo_ret, routine.returnCustomType);
266 }
267
268 const argList = routine.params.map(p => `:${p.name}`).join(', ');
269 const block = `BEGIN ${qualifiedName}(${argList}); END;`;
270 const bindings: Dictionary = {};
271 const refCursorParams: string[] = [];
272
273 for (const p of routine.params) {
274 const value = this.convertRoutineInbound(args[p.name as string], p);
275 const isRefCursor = typeof p.type === 'string' && /sys_refcursor|ref\s*cursor/i.test(p.type);
276
277 if (p.direction === 'in') {
278 bindings[p.name as string] = { dir: oracledb.BIND_IN, val: value };
279 continue;
280 }
281
282 if (isRefCursor) {
283 bindings[p.name as string] = { dir: oracledb.BIND_OUT, type: oracledb.DB_TYPE_CURSOR };
284 refCursorParams.push(p.name as string);
285 continue;
286 }

Callers

nothing calls this directly

Calls 12

isReadOnlyRoutineFunction · 0.85
oracleReturnBindFunction · 0.85
pushMethod · 0.80
entriesMethod · 0.80
filterMethod · 0.80
joinMethod · 0.65
executeMethod · 0.65
testMethod · 0.65
closeMethod · 0.65
quoteIdentifierMethod · 0.45
mapMethod · 0.45

Tested by

no test coverage detected