This *could* be done with pure SQL, but the reality is, that would be
a) probably more complex to read and maintain, and
b) somewhat wasted exercise because we have to call UTL_RAW anyway.
People may say "Hey, use the REVERSE function in SQL", but since its not documented...you're on a slippery slope there.
So here's a simple PLSQL routine to do it - you can pass whether you want them all, or just the largest one(s).
SQL> create or replace
2 type str_list is table of varchar2(4000);
3 /
Type created.
SQL>
SQL> create or replace
2 function list_palindromes(p_str varchar2, p_largest_only varchar2 default 'N') return str_list pipelined is
3 l_str_len int := length(p_str);
4
5 l_candidate varchar2(1000);
6 l_found boolean := false;
7 begin
8 for i in reverse 2 .. l_str_len
9 loop
10 for j in 1 .. l_str_len - i + 1
11 loop
12 l_candidate := substr(p_str,j,i);
13 if upper(l_candidate) = utl_raw.cast_to_varchar2( utl_raw.reverse ( utl_raw.cast_to_raw(upper(l_candidate)))) then
14 pipe row (l_candidate);
15 l_found := true;
16 end if;
17 end loop;
18 if p_largest_only = 'Y' then
19 exit when l_found;
20 end if;
21 end loop;
22 end;
23 /
Function created.
SQL> sho err
No errors.
SQL>
SQL> select * from table(list_palindromes(p_str=>'abaxyzaghjkkjhga'));
COLUMN_VALUE
----------------------------------------------------------------------------------------------------------------------------------
ghjkkjhg
hjkkjh
jkkj
aba
kk
5 rows selected.
SQL>
SQL> select * from table(list_palindromes(p_str=>'abaxyzaghjkkjhga',p_largest_only=>'Y'));
COLUMN_VALUE
----------------------------------------------------------------------------------------------------------------------------------
ghjkkjhg
1 row selected.