String formatting in Oracle (PL/)SQL - oracle

Modern programming languages allows the developer to create strings with placeholders and replaced the correct values with a function/method usually called format. Sometimes, it looks like this:
"Hi {0}! How are you?".format('John');
Is there any function in Oracle SQL or PL/SQL with the same behavior? Or what's the best practice here?

utl_lms package, and specifically format_message() procedure of that package can be used to format a string.
begin
dbms_output.put_line(utl_lms.format_message('Hi %s! How are you %s?.'
, 'John'
, 'John'
)
);
end;
Result:
Hi John! How are you John?.
It should be noted that:
It works only within a PLS/SQL block, not SQL.
You should provide substituting value for every substituted special character (%s for string, %d for numbers) even if they are the same.

Related

Trying to use replace ((value),"\W","") on oracle xquery

Could someone explain why does replace \w (word-character) work and \W (non-word-character) does not .
How to solve it.
create table test (xmldata) as
select xmltype('<workbook>
<worksheet sheetName="asd-kasd" sheetId="1"/>
</workbook>')
from dual;
update test
set XMLDATA=
xmlquery(
'copy $d := .
modify (
for $i in $d/workbook/worksheet/#sheetName
return replace value of node $i with concat("1.\w:",replace(string($i/../#sheetName),"\w",""),"2. \W:",replace($i/../#sheetName,"\W",""))
)
return $d'
passing test.XMLDATA
returning content
);
ORA-19112: error raised during evaluation:
XVM-01126: [FORX0003] Regular expression matches zero-length string
fiddle:
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=ede05cbbe55f36074c36457e9491fc11
Error:
ORA-19112: error raised during evaluation:
XVM-01126: [FORX0003] Regular expression matches zero-length string
after using \W
This seems to be a bug in Oracle's implementation of the standard XQuery fn:replace() function. Using the metacharacter \W causes fn:replace to fail, on every string that I tested. I'd suggest opening a Service Request with Oracle Support to report it.
You can verify using an non-Oracle XQuery tester (e.g. here) that replace() should handle \W just fine.
Oddly, the deprecated ora:replace() function does work correctly. So you could use that as a workaround until Oracle patches the bug. But note that this function is non-standard - for example, it supports POSIX-style metacharacters (e.g. [[:alnum:]]) which the XQuery standard does not.
I simplified your query to give a more minimal verifiable example, and could reproduce the issue on Oracle 12.2.0.1. Comment out the "fn" column to get correct results.
select
regexp_replace('asd-kasd','\W','') as rr, -- normal regexp engine works fine
-- \W fails, with any string
xmlquery('fn:replace("asd-kasd","\W","")' returning content) as fn,
-- deprecated ora:replace works fine
xmlquery('ora:replace("asd-kasd","\W","")' returning content) as ora
from dual
Fiddle

PLSQL - convert UTF-8 NVARCHAR2 to VARCHAR2

I have a table with a column configured as NVARCHAR2, I'm able save the string in UTF-8 without any issues.
But the application the calls the value does not fully support UTF-8.
This means that the string is passed to the database and back after the string is converted into HTML letter code. Each letter in the string is converted to such HTML code.
I'm looking for an easier solution.
I've considered converting it to BASE64, but it contains various characters which are considered illegal in the application.
In addition tried using HEXTORAW & RAWTOHEX.
None of the above helped.
If the column contains 'κόσμε' I need to find a way to convert/encode it to something else, but the decode should be possible to do from the HTML running the application.
Try using ASCIISTR function, it will convert it in something similar as JSON encodes unicode strings (it's actually the same, except "\" is used instead of "\u") and then when you receive it back from front end try using UNISTR to convert it back to unicode.
ASCIISTR: https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions006.htm
UNISTR: https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions204.htm
SELECT ASCIISTR(N'κόσμε') FROM DUAL;
SELECT UNISTR('\03BA\1F79\03C3\03BC\03B5') FROM DUAL;

SQLite3 database insert using variables

I am writing a script that exports results into a SQLite database. I can not get the code to work when I use variables.
Here is an excerpt:
require 'sqlite3'
require 'shodan'
table_name = "#{Date.today.strftime("%B")}#{Time.now.year}_Findings"
db = SQLite3::Database.new "shodan_test.db"
db.execute ("CREATE TABLE #{table_name} (ip string , ports string)")
results = api.host(target)
ip = results["ip_str"].to_s
ports = results["ports"].to_s
db.execute ("insert into #{table_name} (ip, ports) values (#{ip}, #{ports})")
The code fails at the last line. I can remove the variables and the code works. I'm a bit confused since the CREATE TABLE works with a variable.
Your problem is that you're not quoting your strings. The result is that SQLite sees things like
insert into ... values (192.168.0.6, whatever is in ports)
and that's not valid SQL.
SQLite3::Database#execute understands placeholders so you should use them:
db.execute("insert into #{table_name} (ip, ports) values (?, ?)", ip, ports)
The placeholders (?) in the query will be replaced with properly quoted and escaped versions of their values. Using placeholders avoids all the usual quoting and injection problems that plague using string interpolation for SQL.
Also note that I've removed the space between execute and (. If you put a space there then Ruby thinks your "method calling parentheses" are actually "expression grouping parentheses" and it will complain about not understanding what those commas are doing. If you're only passing one argument (such as in db.execute ("CREATE ...")) then it won't matter because the parentheses are effectively ignored but it does matter when there are multiple arguments. In any case, o.m (arg) is a bad habit to get into, you should say o.m(arg) or leave the parentheses out.

ASCII for SYS_CONNECT_BY_PATH ORACLE sql

Is there any way to use ascii code for value separator in SYS_CONNECT_BY_PATH.
For example in SYS_CONNECT_BY_PATH(columnname,'!'),
I want to use the ASCII value of !(33) instead of actual symbol. Also, can i use the ascii value of ENTER (13) as value separator?
Thank you.
You can use the chr function to replace a character with it's numeric equivalent.
SYS_CONNECT_BY_PATH(column name, chr(33))
Or to use a line feed, which should also be fine:
SYS_CONNECT_BY_PATH(column name, chr(13))
It's not strictly ASCII as it depends on your character set, but it will probably work for you. You can see the numeric values using the reverse ascii function, which also isn't really quite ASCII, but again close enough especially if you're always using the same character set. So ascii('!') would give you 33.
As you've discovered, giving anything except a fixed string literal gives:
SQL Error: ORA-30003: illegal parameter in SYS_CONNECT_BY_PATH
function
30003. 00000 - "illegal parameter in SYS_CONNECT_BY_PATH function"
*Cause:
*Action: use a non-empty constant string as the second argument,
then retry the operation.
This is why I usually test things before posting, but this seemed so simple... You can get around that with replace:
REPLACE(SYS_CONNECT_BY_PATH(column name, '/'), '/', chr(33))
Borrowing an example from the manual:
SELECT LPAD(' ', 2*level-1)
||replace(SYS_CONNECT_BY_PATH(last_name, '/'),'/',chr(33)) "Path"
FROM employees
START WITH last_name = 'Kochhar'
CONNECT BY PRIOR employee_id = manager_id;
Path
--------------------------------------------------
!Kochhar
!Kochhar!Greenberg
!Kochhar!Greenberg!Faviet
!Kochhar!Greenberg!Chen
!Kochhar!Greenberg!Sciarra
!Kochhar!Greenberg!Urman
!Kochhar!Greenberg!Popp
!Kochhar!Whalen
!Kochhar!Mavris
!Kochhar!Baer
!Kochhar!Higgins
!Kochhar!Higgins!Gietz
All the credit goes to Sanjeev Chauhan. Update 7/25/2017: This turned out to be a SQL Developer 4.2.0 and 17.2.0 bug. In SQLPlus and SQL Developer 3.2.2 the statement works fine.
Fix: set secureliterals off;
The source is https://community.oracle.com/thread/4065282
I had changed the version from 4.2.0 to 4.1.1.19 and my piece of code worked. Also be aware that I couldn't find "secureliterals" in version 4.2.0

Oracle pl-sql escape character (for a " ' ")

When I am trying to execute INSERT statement in oracle, I got SQL Error: ORA-00917: missing comma error because there is a value as Alex's Tea Factory in my INSERT statement.
How could I escape ' ?
To escape it, double the quotes:
INSERT INTO TABLE_A VALUES ( 'Alex''s Tea Factory' );
In SQL, you escape a quote by another quote:
SELECT 'Alex''s Tea Factory' FROM DUAL
Instead of worrying about every single apostrophe in your statement.
You can easily use the q' Notation.
Example
SELECT q'(Alex's Tea Factory)' FROM DUAL;
Key Components in this notation are
q' which denotes the starting of the notation
( an optional symbol denoting the starting of the statement to be fully escaped.
Alex's Tea Factory (Which is the statement itself)
)' A closing parenthesis with a apostrophe denoting the end of the notation.
And such that, you can stuff how many apostrophes in the notation without worrying about each single one of them, they're all going to be handled safely.
IMPORTANT NOTE
Since you used ( you must close it with )', and remember it's optional to use any other symbol, for instance, the following code will run exactly as the previous one
SELECT q'[Alex's Tea Factory]' FROM DUAL;
you can use ESCAPE like given example below
The '_' wild card character is used to match exactly one character, while '%' is used to match zero or more occurrences of any characters. These characters can be escaped in SQL.
SELECT name FROM emp WHERE id LIKE '%/_%' ESCAPE '/';
The same works inside PL/SQL:
if( id like '%/_%' ESCAPE '/' )
This applies only to like patterns, for example in an insert there is no need to escape _ or %, they are used as plain characters anyhow. In arbitrary strings only ' needs to be escaped by ''.
SELECT q'[Alex's Tea Factory]' FROM DUAL
Your question implies that you're building the INSERT statement up by concatenating strings together. I suggest that this is a poor choice as it leaves you open to SQL injection attacks if the strings are derived from user input. A better choice is to use parameter markers and to bind the values to the markers. If you search for Oracle parameter markers you'll probably find some information for your specific implementation technology (e.g. C# and ADO, Java and JDBC, Ruby and RubyDBI, etc).
Share and enjoy.
Here is a way to easily escape & char in oracle DB
set escape '\\'
and within query write like
'ERRORS &\\\ PERFORMANCE';

Resources