Search notes:

Oracle: SQL statement

Identifiying SQL Statements

sql_id

An SQL statement (or more accurately its text) is identified by an SQL ID which is a base 32 representation of the last 8 bytes of kglnahsv in x$kglob. The hash value is just another fancy representation of the SQL ID.
These values are used to find SQL statements in several places, for example in v$sql.
declare
   sql_md5    raw(16);
   hash_      raw(16);
   
   subtype dword is raw(4);

   sqlid_num number;
   sqlid     varchar2(13);

   type  dword_4 is varray(4) of dword;
   parts dword_4 := dword_4();

   sql_hash  varchar2(100);

begin

   sql_md5 := dbms_crypto.hash(
            utl_i18n.string_to_raw('select 42 from dual' || chr(0), 'AL32UTF8'),
            dbms_crypto.hash_md5
   );

   dbms_output.put_line('MD5 of SQL: ' || sql_md5);
  
   parts.extend(4);
   for i in 1 .. 4 loop
       parts(i) := utl_raw.substr(sql_md5, (i-1)*4+1, 4);
       parts(i) := utl_raw.reverse(parts(i));             -- Little/big endian?
  
   end loop;
  
   hash_ := utl_raw.concat(parts(1), parts(2), parts(3), parts(4));
  
   dbms_output.put_line('Hash: ' || hash_);

   for ob in (select * from x$kglob where kglnahsv = lower(hash_)) loop
       dbms_output.put_line(ob.kglnaobj);
   end loop;

   ------

-- declare
-- v_temp NUMBER := TO_NUMBER(RAWTOHEX(UTL_RAW.reverse(UTL_RAW.SUBSTR(v_md5, 9, 4)))|| RAWTOHEX(UTL_RAW.reverse(UTL_RAW.SUBSTR(v_md5, 13, 4))),RPAD('x', 16, 'x'));

   sqlid_num := to_number(
      rawtohex( utl_raw.concat(parts(3), parts(4) ) ),
      rpad('x', 16, 'x')
   );

   select 
      listagg(
         substr('0123456789abcdfghjkmnpqrstuvwxyz',
         mod(
           trunc(sqlid_num/power(32,level-1)),
           32 
         ) + 1 ,
         1
       ) 
   ) within group (order by level desc) into sqlid
   from dual 
   connect by level <= ceil(log(32, sqlid_num + 1));

   dbms_output.put_line('SQLID: ' || sqlid);

   for s in (select * from v$sql where v$sql.sql_id = sqlid) loop
       dbms_output.put_line(s.sql_text);
   end loop;

--
-- Convert sql_id to hash
-- Algorithm found @ Tanel's Poder website
--   https://tanelpoder.com/2009/02/22/sql_id-is-just-a-fancy-representation-of-hash-value
--   https://github.com/tanelpoder/tpt-oracle/blob/master/i2h.sql
--
   select
       trunc(mod(sum(( instr('0123456789abcdfghjkmnpqrstuvwxyz',substr(lower(trim(sqlid)),level,1))-1)*power(32,length(trim(sqlid))-level)),power(2,32))) into sql_hash
   from
       dual
   connect by
       level <= length(trim(sqlid));

   dbms_output.put_line('Hash: ' || sql_hash);

   for s in (select * from v$sql where v$sql.hash_value = sql_hash) loop
       dbms_output.put_line(s.sql_text);
   end loop;

   dbms_output.put_line('dbms_utility.sqlid_to_sqlhash(): ' || dbms_utility.sqlid_to_sqlhash(sqlid));

end;
/
Of course, an sql id can be calculated much easier with dbms_sql_translator.sql_id.
See also the SQL*Plus predefined variable _sql_id and the SQL*Plus command set feedback on sql_id.

sql_exec_id

force_matching_signature / exact_matching_signature

An SQL statement's signature is calculated by hashing the text of the SQL statement after changing its keywords to uppercase and removing whitespace.
Thus, a signature, identifies statements that execute equally. Multiple SQL IDs map to the same signature.
select
   count(*) over (partition by force_matching_signature) cnt,
   force_matching_signature,
   sql_id,
   sql_fulltext
from
   v$sqlarea
where
   force_matching_signature <> 0
order by
   cnt desc;
select
   dbms_sqltune.sqltext_to_signature('select  count(abc) from def where ghi = 9 and bitand(flags, 128) = 0', force_match=>1) sig_1,
   dbms_sqltune.sqltext_to_signature('select count( abc) from def where ghi = 7 and bitand(flags,  65) = 1', force_match=>1) sig_2
from
   dual;

Same SQL statement with different execution plan

The same SQL statement can be executed with different execution plans.
Thus, in order to identify the plan for an sql_id, the child number is also required.
Alternatively, a plan can also be identified (although without sql_id) using the plan hash value or full plan hash value.

Different SQL statements with the same execution plan

Different SQL statements (i. e. with different SQL IDs) don't necessarily have different execution plan.

Statement-level atomicity

In Oracle, an SQL statement runs with so called «statement-level atomicity» which means that the statement either completely succeeds or completely fails.
If the statement fails, only the effects of the statement are rolled back.

Comments

ORA-01756: quoted string not properly terminated

The following two «comments» cause a ORA-01756: quoted string not properly terminated
begin
    dbms_output.put_line('foo');
/*
    dbms_output.put_line('*/');
*/
end;
/
begin
   dbms_output.put_line('two
lines');
-- dbms_output.put_line('two
lines');

end;
/

TODO

Internally, Oracle uses the functions rpisplu(), kprbprs(), opiprs() and OCIStmtPrepare() to parse SQL Statements.

See also

When Oracle is requested to execute an SQL statement, the optimizer tries to determine the most efficient way to to so, resulting in a so-called execution plan.
Execute dynamic SQL Statements in PL/SQL with
Semantically parse SQL statements with utl_xml.parseQuery
The maximum length of a query is recorded in dba_high_water_mark_statistics.
The PL/SQL package sql_stmt.
dba_statements lists SQL statements that are found in PL/SQL objects.
The init parameter plscope_settings.
dbms_utility.expand_sql_text translates an SQL statement into a semantically equivalent one which does not reference any views or synonyms (only references tables).
The two PL/SQL exception related functions sqlerrm and sqlcode cannot be used in an SQL statement.
Using servererror triggers to catch erroneous SQL statements.
In Oracle SQL Developer, the text of an SQL statement can be formatted by pressing the keyboard shortcut ctrl+F7.
Starting with 23c, the last 52 (or so…) executed SQL statements can be queried from v$sql_history.
See also dba_hist_sqlstat
bind variable
dbms_cloud_ai uses LLMs to generate SQL statements from natural language prompts.

Index