Oracle Internal Core : Les fonctions Oracle et le package PL/SQL STANDARD - Oracle functions and STANDARD PL / SQL package
Introduction
Je poursuis mon exploration des "entrailles" de la base Oracle (les américains parlent de "Oracle Internal" voir "Oracle Core Internal") pour comprendre un peu mieux comment elle fonctionne et surtout sur quels piliers elle repose. J'ai déjà fais des articles sur les structures mémoires X$xxx appelées Fixed Tables, les vraies tables du dictionnaire de données xxx$ (voir article "Trouver les objets Oracle cachés avec le dictionnaire de données"). Aujourd'hui je vais m'attaquer aux fonctions SQL telles qu'elles sont gérées dans Oracle, comment elles sont implémentées et où trouver leur définition.
Points d'attention
Aucun.
Base de tests
N'importe quelle base Oracle.
Exemples
============================================================================================
Les packages STANDARD et DBMS_STANDARD
============================================================================================
Je travaille sur une base 12c architecture CDB et je suis connecté sur le CDB$ROOT.
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
PL/SQL Release 12.2.0.1.0 - Production
CORE 12.2.0.1.0 Production
TNS for Linux: Version 12.2.0.1.0 - Production
NLSRTL Version 12.2.0.1.0 - Production
SQL> select CDB from v$database;
CDB
---
YES
SQL> show con_name
CON_NAME
------------------------------
CDB$ROOT
Sous Oracle, il existe deux packages PL/SQL de nom STANDARD et DBMS_STANDARD, appartenant à SYS. C'est le point d'entrée pour notre recherche.
SQL> col OWNER for a30
SQL> col OBJECT_NAME for a30
SQL> col PROCEDURE_NAME for a30
SQL> break on owner on OBJECT_NAME on PROCEDURE_NAME
SQL> select distinct owner, OBJECT_NAME, OBJECT_TYPE from DBA_PROCEDURES where OBJECT_NAME like '%STANDARD%' order by owner, OBJECT_TYPE, OBJECT_NAME;
OWNER OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------ -------------
LBACSYS LBAC_STANDARD PACKAGE
SYS DBMS_STANDARD PACKAGE
SYS STANDARD PACKAGE
Regardons le contenu de ces packages. Chacun contient des dizaines de procédures, correspondant notamment aux commandes SQL. A noter que le type de ces commandes est PACKAGE et pas FUNCTION ou PROCEDURE. C'est le package STANDARD qui renferme ces commandes SQL; même si DBMS_STANDARD a une fonction comme COMMIT (commande SQL*Plus soit dit en passant).
La doc Oracle n'est pas loquace sur ces package, voici ce que dit Morgan sur son excellent site.
- STANDARD https://www.morganslibrary.org/reference/pkgs/standard.html : "Essentially every Oracle built-in function, package, procedure, and type is dependent on the STANDARD package. You can not do much more than stare at the command-line without interacting with this package."
- DBMS_STANDARD https://www.morganslibrary.org/reference/pkgs/dbms_standard.html : "Kernel extensions to the package STANDARD".
Je mets en bleu quelques ligne intéressantes mais c'est purement subjectif. A noter que des fonctions SQL comme MAX sont absentes de ce package, allez savoir pourquoi.
SQL> select distinct owner, OBJECT_NAME, PROCEDURE_NAME, OBJECT_TYPE from DBA_PROCEDURES where OBJECT_NAME like '%STANDARD%' order by owner, OBJECT_TYPE, OBJECT_NAME;
OWNER OBJECT_NAME PROCEDURE_NAME OBJECT_TYPE
------------------------------ ----------------------------------
LBACSYS LBAC_STANDARD RAISE_FACILITY_ERROR PACKAGE
RESET_TRUSTED_PROG PACKAGE
SET_TRUSTED_PROG PACKAGE
PACKAGE
SYS DBMS_STANDARD APPLYING_CROSSEDITION_TRIGGER PACKAGE
CLIENT_IP_ADDRESS PACKAGE
COMMIT PACKAGE
COMMIT_CM PACKAGE
DATABASE_NAME PACKAGE
DELETING PACKAGE
DES_ENCRYPTED_PASSWORD PACKAGE
DICTIONARY_OBJ_NAME PACKAGE
DICTIONARY_OBJ_NAME_LIST PACKAGE
DICTIONARY_OBJ_OWNER PACKAGE
DICTIONARY_OBJ_OWNER_LIST PACKAGE
DICTIONARY_OBJ_TYPE PACKAGE
GRANTEE PACKAGE
INSERTING PACKAGE
INSTANCE_NUM PACKAGE
IS_ALTER_COLUMN PACKAGE
IS_CREATING_NESTED_TABLE PACKAGE
IS_DROP_COLUMN PACKAGE
IS_SERVERERROR PACKAGE
LOGIN_USER PACKAGE
ORA_MAX_NAME_LEN_SUPPORTED PACKAGE
ORIGINAL_SQL_TXT PACKAGE
PARTITION_POS PACKAGE
PRIVILEGE_LIST PACKAGE
RAISE_APPLICATION_ERROR PACKAGE
REVOKEE PACKAGE
ROLLBACK_NR PACKAGE
ROLLBACK_SV PACKAGE
SAVEPOINT PACKAGE
SERVER_ERROR PACKAGE
SERVER_ERROR_DEPTH PACKAGE
SERVER_ERROR_MSG PACKAGE
SERVER_ERROR_NUM_PARAMS PACKAGE
SERVER_ERROR_PARAM PACKAGE
SET_TRANSACTION_USE PACKAGE
SQL_TXT PACKAGE
SYSEVENT PACKAGE
SYS_GETTRIGGERSTATE PACKAGE
UPDATING PACKAGE
WITH_GRANT_OPTION PACKAGE
PACKAGE
STANDARD SYS$DSINTERVALSUBTRACT PACKAGE
SYS$EXTRACT_FROM PACKAGE
SYS$EXTRACT_STRING_FROM PACKAGE
SYS$STANDARD_CHR PACKAGE
SYS$STANDARD_JSON PACKAGE
SYS$STANDARD_TRANSLATE PACKAGE
SYS$STANDARD_TRIM PACKAGE
SYS$YMINTERVALSUBTRACT PACKAGE
ABS PACKAGE
ACOS PACKAGE
ADD_MONTHS PACKAGE
ASCII PACKAGE
ASCIISTR PACKAGE
ASIN PACKAGE
ATAN PACKAGE
ATAN2 PACKAGE
BFILENAME PACKAGE
BITAND PACKAGE
CARDINALITY PACKAGE
CEIL PACKAGE
CHARTOROWID PACKAGE
CHR PACKAGE
COALESCE PACKAGE
COMMIT PACKAGE
COMMIT_CM PACKAGE
COMPOSE PACKAGE
CONCAT PACKAGE
CONTINUE PACKAGE
CONVERT PACKAGE
COS PACKAGE
COSH PACKAGE
CUBE PACKAGE
CURRENT_DATE PACKAGE
CURRENT_TIME PACKAGE
CURRENT_TIMESTAMP PACKAGE
DBTIMEZONE PACKAGE
DECODE PACKAGE
DECOMPOSE PACKAGE
DEREF PACKAGE
DUMP PACKAGE
EMPTY_BLOB PACKAGE
EMPTY_CLOB PACKAGE
EXISTS PACKAGE
EXP PACKAGE
FLOOR PACKAGE
FROM_TZ PACKAGE
GLB PACKAGE
GREATEST PACKAGE
GREATEST_LB PACKAGE
GROUPING PACKAGE
HEXTORAW PACKAGE
INITCAP PACKAGE
INSTR PACKAGE
INSTR2 PACKAGE
INSTR4 PACKAGE
INSTRB PACKAGE
INSTRC PACKAGE
ISNCHAR PACKAGE
LAST_DAY PACKAGE
LEAST PACKAGE
LEAST_UB PACKAGE
LENGTH PACKAGE
LENGTH2 PACKAGE
LENGTH4 PACKAGE
LENGTHB PACKAGE
LENGTHC PACKAGE
LEVEL PACKAGE
LN PACKAGE
LOCALTIME PACKAGE
LOCALTIMESTAMP PACKAGE
LOG PACKAGE
LOWER PACKAGE
LPAD PACKAGE
LTRIM PACKAGE
LUB PACKAGE
MONTHS_BETWEEN PACKAGE
NANVL PACKAGE
NCHARTOROWID PACKAGE
NCHR PACKAGE
NEW_TIME PACKAGE
NEXT_DAY PACKAGE
NHEXTORAW PACKAGE
NLSSORT PACKAGE
NLS_CHARSET_DECL_LEN PACKAGE
NLS_CHARSET_ID PACKAGE
NLS_CHARSET_NAME PACKAGE
NLS_INITCAP PACKAGE
NLS_LOWER PACKAGE
NLS_UPPER PACKAGE
NULLFN PACKAGE
NULLIF PACKAGE
NUMTODSINTERVAL PACKAGE
NUMTOYMINTERVAL PACKAGE
NVL PACKAGE
POWER PACKAGE
RAWTOHEX PACKAGE
RAWTONHEX PACKAGE
REF PACKAGE
REGEXP_COUNT PACKAGE
REGEXP_INSTR PACKAGE
REGEXP_LIKE PACKAGE
REGEXP_REPLACE PACKAGE
REGEXP_SUBSTR PACKAGE
REMAINDER PACKAGE
REPLACE PACKAGE
ROLLBACK_NR PACKAGE
ROLLBACK_SV PACKAGE
ROLLUP PACKAGE
ROUND PACKAGE
ROWID PACKAGE
ROWIDTOCHAR PACKAGE
ROWIDTONCHAR PACKAGE
ROWLABEL PACKAGE
ROWNUM PACKAGE
RPAD PACKAGE
RTRIM PACKAGE
SAVEPOINT PACKAGE
SESSIONTIMEZONE PACKAGE
SET PACKAGE
SET_TRANSACTION_USE PACKAGE
SIGN PACKAGE
SIN PACKAGE
SINH PACKAGE
SOUNDEX PACKAGE
SQLCODE PACKAGE
SQLERRM PACKAGE
SQRT PACKAGE
SUBSTR PACKAGE
SUBSTR2 PACKAGE
SUBSTR4 PACKAGE
SUBSTRB PACKAGE
SUBSTRC PACKAGE
SYS$LOB_REPLICATION PACKAGE
SYSDATE PACKAGE
SYSTIMESTAMP PACKAGE
SYS_AT_TIME_ZONE PACKAGE
SYS_CONTEXT PACKAGE
SYS_EXTRACT_UTC PACKAGE
SYS_GUID PACKAGE
SYS_LITERALTODATE PACKAGE
SYS_LITERALTODSINTERVAL PACKAGE
SYS_LITERALTOTIME PACKAGE
SYS_LITERALTOTIMESTAMP PACKAGE
SYS_LITERALTOTZTIME PACKAGE
SYS_LITERALTOTZTIMESTAMP PACKAGE
SYS_LITERALTOYMINTERVAL PACKAGE
TAN PACKAGE
TANH PACKAGE
TO_ANYLOB PACKAGE
TO_BINARY_DOUBLE PACKAGE
TO_BINARY_FLOAT PACKAGE
TO_BLOB PACKAGE
TO_CHAR PACKAGE
TO_CLOB PACKAGE
TO_DATE PACKAGE
TO_DSINTERVAL PACKAGE
TO_LABEL PACKAGE
TO_MULTI_BYTE PACKAGE
TO_NCHAR PACKAGE
TO_NCLOB PACKAGE
TO_NUMBER PACKAGE
TO_RAW PACKAGE
TO_SINGLE_BYTE PACKAGE
TO_TIME PACKAGE
TO_TIMESTAMP PACKAGE
TO_TIMESTAMP_TZ PACKAGE
TO_TIME_TZ PACKAGE
TO_YMINTERVAL PACKAGE
TRANSLATE PACKAGE
TRIM PACKAGE
TRUNC PACKAGE
TZ_OFFSET PACKAGE
UID PACKAGE
UNISTR PACKAGE
UPPER PACKAGE
UROWID PACKAGE
USER PACKAGE
USERENV PACKAGE
VALUE PACKAGE
VSIZE PACKAGE
XOR PACKAGE
PACKAGE --> ce n'est pas un mauvais copier/coller, le champ PROCEDURE_NAME est vide pour cet enregistrement...
227 rows selected.
============================================================================================
Détail du package STANDARD
============================================================================================
Je vais me focaliser sur le package STANDARD car c'est lui le plus interne si on compare avec DBMS_STANDARD et, comme le dit Morgan, il est systématiquement sollicité dès qu'on fait du SQL. Si on fait un DESC du package STANDARD, les fonctions/procédures sont listées avec leurs arguments et leur type. Je n'ai mis ici qu'une sélection, il y en a beaucoup trop. Ce qui est cool c'est de voir les variantes car une commande peut prendre des arguments différents en nombre et en type et ici on a la liste de ces variantes, comme TO_CHAR par exemple.
SQL> desc standard
FUNCTION ABS RETURNS NUMBER
Argument Name Type In/Out Default?
------------------------------ ----------------------- --
N NUMBER IN
Certaines fonctions n'ont pas d'arguments.
FUNCTION CUBE RETURNS NUMBER
FUNCTION CURRENT_DATE RETURNS DATE
FUNCTION CURRENT_TIME RETURNS TIME WITH TIME ZONE
FUNCTION CURRENT_TIMESTAMP RETURNS TIMESTAMP WITH TIME ZONE
FUNCTION DBTIMEZONE RETURNS VARCHAR2
TO_CHAR et ses 23 variantes...
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
RIGHT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT DATE IN
RIGHT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT NUMBER IN
RIGHT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LABEL RAW MLSLABEL IN
FORMAT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT DATE IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT NUMBER IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT TIME IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT TIME IN
FORMAT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT TIME WITH TIME ZONE IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT TIME WITH TIME ZONE IN
FORMAT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT TIMESTAMP IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT TIMESTAMP IN
FORMAT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT TIMESTAMP WITH TIME ZONE IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT TIMESTAMP WITH TIME ZONE IN
FORMAT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT TIMESTAMP WITH LOCAL TIME ZONE IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT TIMESTAMP WITH LOCAL TIME ZONE IN
FORMAT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT INTERVAL YEAR TO MONTH IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT INTERVAL YEAR TO MONTH IN
FORMAT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT INTERVAL DAY TO SECOND IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT INTERVAL DAY TO SECOND IN
FORMAT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT BINARY_FLOAT IN
FORMAT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT BINARY_DOUBLE IN
FORMAT VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT BINARY_FLOAT IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
FUNCTION TO_CHAR RETURNS VARCHAR2
Argument Name Type In/Out Default?
------------------------------ -----------------------
LEFT BINARY_DOUBLE IN
FORMAT VARCHAR2 IN
PARMS VARCHAR2 IN
============================================================================================
Le code de création du package STANDARD
============================================================================================
La définition des fonctions du package STANDARD est dans le fichier $ORACLE_HOME/rdbms/admin/stdspec.sql. Dans ce fichier n'est présente que l'interface du package PL/SQL avec ses fonctions, pas le code ou body (pour ça, on verra stdbody.sql).
Extrait de ce fichier.
...
create or replace
package STANDARD AUTHID CURRENT_USER is
/********** Function, operators and procedures **********/
function "EXISTS" return BOOLEAN;
pragma BUILTIN('EXISTS',10,240,240); -- This is special cased in PH2 -- Pj
function GREATEST (pattern NUMBER) return NUMBER;
pragma BUILTIN('GREATEST',12,240,240);-- This is special cased in PH2 -- Pj
function GREATEST (pattern VARCHAR2 CHARACTER SET ANY_CS)
return VARCHAR2 CHARACTER SET pattern%CHARSET;
pragma BUILTIN('GREATEST',12,240,240);-- This is special cased in PH2 -- Pj
function GREATEST (pattern DATE) return DATE;
pragma BUILTIN('GREATEST',12,240,240);-- This is special cased in PH2 -- Pj
Tiens, les opérateurs arithmétiques sont eux aussi des fonctions?
function '+' (LEFT DATE, RIGHT NUMBER) return DATE;
pragma BUILTIN('+',14, 12, 7); -- PEMS_DATE, DATE_ADD1
pragma FIPSFLAG('+', 1450);
function '+' (LEFT NUMBER, RIGHT DATE) return DATE;
pragma BUILTIN('+',14, 12, 8); -- PEMS_DATE, DATE_ADD2
pragma FIPSFLAG('+', 1450);
Pour aller ENCORE plus loin, et accéder à une partie du code de ces fonctions, un petit tour dans $ORACLE_HOME/rdbms/admin/stdbody.sql :-)
La fonction SYSDATE appelle une fonction plus interne, pessdt.
function sysdate return date is
d date;
begin
d := pessdt;
return d;
exception
when ICD_UNABLE_TO_COMPUTE then
select sysdate into d from sys.dual;
return d;
end;
Amusant, on a même des commentaires des développeurs Oracle :-) Là, on est vraiment au plus proche possible du coeur du SGBD si on n'est pas développeur chez Oracle!!!
Je le traduit en français? "Pourquoi avons-nous besoin de ces stupides déclarations pour les fonctions LEVEL et ROWNUM?).
-- why do we need these dummy bodies for LEVEL and ROWNUM?
function LEVEL return NUMBER is
begin return 0.0; end;
function ROWNUM return NUMBER is
begin return 0.0; end;
Là, on a carrément le code de NVL, sans même un appel à une autre fonction plus interne!
-- This body is required, and will be called
function NVL (B1 "<REF_CURSOR_1>", B2 "<REF_CURSOR_1>")
return "<REF_CURSOR_1>" is
begin
if (B1 IS NULL) then return(B2); else return(B1); end if;
end NVL;
On a aussi le code qui traite les ordres DDL.
La procédure COMMIT appelle la procédure SQL_DDL qui doit valider la commande.
procedure COMMIT is
Begin
SQL_DDL('COMMIT');
End;
La procédure SQL_DDL appelle la fonction plzsql qui exécute réellement la commande DDL.
procedure SQL_DDL(Stmt VARCHAR2) i
rc Binary_Integer;
DDL_ERROR exception;
Begin
rc := plzsql(Stmt);
if ( rc IS NOT NULL ) then
RAISE DDL_ERROR;
end if;
End;
Et on a même des infos sur plzsql ... Pfiou, quel voyage :-)
FUNCTION plzsql(stmt VARCHAR2) RETURN binary_integer;
PRAGMA interface (c,plzsql);
Je ne pense pas qu'on puisse aller plus loin puisque cette fonction plzsql n'est connue que de ce package.
[oracle@vbgeneric admin]$ pwd
/u01/app/oracle/product/12.2/db_1/rdbms/admin
[oracle@vbgeneric admin]$ grep -i plzsql * | more
grep: cdb_cloud: Is a directory
stdbody.sql: FUNCTION plzsql(stmt VARCHAR2) RETURN binary_integer;
stdbody.sql: PRAGMA interface (c,plzsql);
stdbody.sql: rc := plzsql(Stmt);
Hé bien si, j'ai trouvé!!!!!
En faisant une recherche Google sur plzsql, je tombe sur ce site https://yurichev.com/blog/50/ où il est marqué que l'interface PRAGMA est "a gateway to internal Oracle functions." et, ici http://www.petefinnigan.com/weblog/archives/00000835.htm que c'est une interface développée en C. Ici https://www.morganslibrary.org/reference/plsql/pragma.html on dit que "A pragma is a compiler directive that tells Oracle to use rules, other than the default rules, for the object.". Un exemple connu est AUTONOMOUS_TRANSACTION Pragma.
============================================================================================
Autres points
============================================================================================
A noter qu'au niveau des synonymes, il n'en existe aucun pour STANDARD.
SQL> select owner, SYNONYM_NAME, TABLE_OWNER, TABLE_NAME from dba_synonyms where SYNONYM_NAME like '%STANDARD%' order by OWNER, SYNONYM_NAME;
OWNER SYNONYM_NAME TABLE_OWNE TABLE_NAME
---------- --------------- ---------- ---------------
PUBLIC DBMS_STANDARD SYS DBMS_STANDARD
Ce qui est bizarre d'ailleurs car pour appeler les fonctions de ce package, on peut les préfixer ou non par le nom du package et même du propriétaire...
SQL> select nvl(NULL, 'OK') from dual;
NV
--
OK
SQL> select standard.nvl(NULL, 'OK') from dual;
STANDARD.NVL(NULL,'OK')
-----------------------
OK
SQL> select sys.standard.nvl(NULL, 'OK') from dual;
SYS.STANDARD.NVL(NULL,'OK')
---------------------------
OK
Ca ne marche pas pour les fonctions absentes de ce package bien sur.
SQL> select max(1) from dual;
MAX(1)
----------
1
SQL> select standard.max(1) from dual;
select standard.max(1) from dual
*
ERROR at line 1:
ORA-00904: "SYS"."STANDARD"."MAX": invalid identifier
SQL> select sys.standard.max(1) from dual;
select sys.standard.max(1) from dual
*
ERROR at line 1:
ORA-00904: "SYS"."STANDARD"."MAX": invalid identifier
Tiens, même échec avec la fonction +. Elle est certes absente du package STANDARD mais présente dans stdspec.sql.
function '+' (RIGHT NUMBER) return NUMBER;
pragma BUILTIN('+',14, 0, 1); -- PEMS_QUICK
SQL> select 1 + 1 from dual;
1+1
----------
2
SQL> select 1 standard.+ 1 from dual;
select 1 standard.+ 1 from dual
*
ERROR at line 1:
ORA-00923: FROM keyword not found where expected
SQL> select sys.standard.+ 1 from dual;
select sys.standard.+ 1 from dual
*
ERROR at line 1:
ORA-01747: invalid user.table.column, table.column, or column specification
Et voilà, c'est fini pour cette fois! A un prochain voyage dans les "entrailles" d'Oracle!!!!!!