@@ -15,6 +15,7 @@ import {
1515 type EmitConfig ,
1616 type TypeEntry ,
1717} from "../emission/emit.ts" ;
18+ import type { EmitFn } from "../emission/facts.ts" ;
1819import {
1920 introspect ,
2021 ORACLE_CAST_TARGET ,
@@ -61,6 +62,71 @@ const CONFIG: EmitConfig = {
6162 typeTable : new Map ( TYPES . map ( ( t ) => [ t . typname , t ] ) ) ,
6263 noMethod : new Set ( [ "coalesce" , "in" ] ) ,
6364} ;
65+
66+ // Oracle's catalogs describe ordinary functions well, but expose
67+ // operators as undocumented optimizer names and leave a few ubiquitous
68+ // functions untyped. Keep this deliberately small and SQL-verified.
69+ const ORACLE_SUPPLEMENT : EmitFn [ ] = [
70+ ...[ "+" , "-" , "*" , "/" ] . map ( ( sql ) : EmitFn => ( {
71+ sql,
72+ kind : "binop" ,
73+ overloads : [ "number" , "binary_float" , "binary_double" ] . map ( ( type ) => ( {
74+ args : [ { type } , { type } ] , returns : type , nullability : "propagates" ,
75+ } ) ) ,
76+ } ) ) ,
77+ {
78+ sql : "-" , kind : "unaryop" ,
79+ overloads : [ "number" , "binary_float" , "binary_double" ] . map ( ( type ) => ( {
80+ args : [ { type } ] , returns : type , nullability : "propagates" ,
81+ } ) ) ,
82+ } ,
83+ {
84+ sql : "+" , kind : "binop" ,
85+ overloads : [
86+ { args : [ { type : "date" } , { type : "number" } ] , returns : "date" , nullability : "propagates" } ,
87+ { args : [ { type : "timestamp" } , { type : "intervalds" } ] , returns : "timestamp" , nullability : "propagates" } ,
88+ ] ,
89+ } ,
90+ {
91+ sql : "-" , kind : "binop" ,
92+ overloads : [
93+ { args : [ { type : "date" } , { type : "number" } ] , returns : "date" , nullability : "propagates" } ,
94+ { args : [ { type : "date" } , { type : "date" } ] , returns : "number" , nullability : "propagates" } ,
95+ { args : [ { type : "timestamp" } , { type : "timestamp" } ] , returns : "intervalds" , nullability : "propagates" } ,
96+ { args : [ { type : "timestamp" } , { type : "intervalds" } ] , returns : "timestamp" , nullability : "propagates" } ,
97+ ] ,
98+ } ,
99+ ...[ "LIKE" , "NOT LIKE" ] . map ( ( sql ) : EmitFn => ( {
100+ sql,
101+ kind : "binop" ,
102+ overloads : [ {
103+ args : [ { type : "varchar2" } , { type : "varchar2" } ] ,
104+ returns : "bool" ,
105+ nullability : "propagates" ,
106+ } ] ,
107+ } ) ) ,
108+ {
109+ sql : "LNNVL" , kind : "scalar" ,
110+ overloads : [ { args : [ { type : "bool" } ] , returns : "bool" , nullability : "never" } ] ,
111+ } ,
112+ {
113+ sql : "WIDTH_BUCKET" , kind : "scalar" ,
114+ overloads : [ {
115+ args : [ "number" , "number" , "number" , "number" ] . map ( ( type ) => ( { type } ) ) ,
116+ returns : "number" ,
117+ nullability : "propagates" ,
118+ } ] ,
119+ } ,
120+ {
121+ sql : "NVL2" , kind : "scalar" ,
122+ overloads : [ "number" , "varchar2" , "bool" ] . map ( ( type ) => ( {
123+ args : [ { type : "any" } , { type } , { type } ] ,
124+ returns : type ,
125+ nullability : "propagates" as const ,
126+ nullPositions : [ 1 , 2 ] ,
127+ } ) ) ,
128+ } ,
129+ ] ;
64130const OVERRIDE_NAMES = scanOverrideNames ( OVERRIDES_DIR ) ;
65131
66132const chromeFor = ( typname : OracleTypname ) : ClassChrome => {
@@ -95,7 +161,7 @@ export const generate = async (): Promise<void> => {
95161 generatedDir : GENERATED_DIR ,
96162 barrelPath : TYPES_INDEX ,
97163 types : TYPES ,
98- facts : await introspect ( conn ) ,
164+ facts : [ ... await introspect ( conn ) , ... ORACLE_SUPPLEMENT ] ,
99165 cfg : CONFIG ,
100166 chromeFor : ( t ) => chromeFor ( t . typname as OracleTypname ) ,
101167 overrides : OVERRIDE_NAMES ,
0 commit comments