How to find character code in PL/SQL? - sql

I want to find character code of particular character in string.
For instance if I have a string
"Hello"
How do i find the character code of all or particular characters in the string.
I see that PL/SQL has a ASCII() and ASCIISTR() functions but I could not find any character related functions.

create or replace function asciistr2(s IN varchar2)
RETURN varchar2
IS
result varchar2(32767) := '';
BEGIN
FOR i IN 1..Length(s)
LOOP
dbms_output.put_line(ASCII(substr(s,i,1)));
result := result || ASCII(substr(s,i,1));
END LOOP;
return result;
END;
Select asciistr2('HELLO') from dual
Result: 7269767679
dbms_output
72
69
76
76
79

What exactly would you expect? Looking at your question, it seems to me that ASCII() would give you what you need, see this ASCII tutorial. You can loop
Or are you referring to the Unicode value?

Related

Create Password Verification Function for Enterprise PostgreSQL

How is it possible to create a function in EDB PostgreSQL to check the password?
The password should contain:
at least 1 upper case
at least 1 lower case
at least 1 digit
at least 8 characters long
at least 1 special character
So far I searched and got
CREATE OR REPLACE FUNCTION verify_password(user_name varchar2, new_password varchar2, old_password varchar2)
RETURN boolean IMMUTABLE
IS
BEGIN
IF (length(new_password) < 5)
THEN
raise_application_error(-20001, 'too short');
END IF;
IF substring(new_password FROM old_password) IS NOT NULL
THEN
raise_application_error(-20002, 'includes old password');
END IF;
RETURN true;
END;
Above functions works fine but I am not able to add checks for uppercase, lowercase and special character.
If I add lines on checks for uppercase, lowercase and special character I am able to create the function but when password checks comes in it does not seem to work.

Unexpected result in RPAD

I am using Oracle 11g. I am using the Scott account and the demo EMP table. I inserted one record with ENAME BRUCE WILLIAM. My aim is to show the first name and last name in two columns. I used this code:
select trim rpad(ename, instr(ename,' '))) "First Name",
trim(substr(ename, instr(ename,' '))) "Last Name"
from emp;
This gives a weird result. The First Name is extended to second line. I used
select trim(substr(ename, 1, instr(ename,' '))),
trim(substr(ename, instr(ename, ' ')))
from emp;
I got the expected output. My question is why the first line of query is giving extra spaces?
You are not getting extra spaces in your string, and if you were then the trim() would remove them again. SQL*Plus is just formatting the results in a way you don't expect. The documentation mentions the default formatting for column types, and can usually work it out for system functions (though the characterset can make it bigger than you expect).
It seems like SQL*Plus, and SQL Developer, can't determine a sensible default for your rpad case, but can for your substr. Well, SQL*Plus is really just getting a result set cursor from the database, and using the cursor metadata to determine the default widths to apply to the fields for display, so it isn't getting the length you expect from that metadata. But what length should it use?
The database only knows how big the rpad value can be if the padding length is a simple value - it doesn't even mind zero (it returns null, which you're relying on). If the padding length is determined by a function then there's no way to tell how big the result could be, apart from calculating it for every value in the result set before returning the metadata and and actual data, which isn't practical, and would produce inconsistent output as the data changed.
It also wouldn't be practical to try to determine a theoretical maximum, even though it looks superficially straightforward in your case. substr can't ever return something longer than the original value; but rpad could potentially produce something huge even from a short input value, so it has to allow for that possibility if it can't easily determine a limit (i.e. from a fixed value).
So it plays safe and allows for it being up to the maximum length for a varchar2, which is 4000 characters, as this dynamic SQL demonstrates:
declare
l_curid integer;
l_desctab dbms_sql.desc_tab3;
l_colcnt integer;
begin
l_curid := dbms_sql.open_cursor;
dbms_sql.parse(l_curid, 'select rpad(ename, instr(ename,'' '')), '
|| 'rpad(ename, 4), '
|| 'substr(ename, 1, instr(ename,'' '')) '
|| 'from emp where ename like ''B%''' , dbms_sql.native);
dbms_sql.describe_columns3(l_curid, l_colcnt, l_desctab);
for i in 1 .. l_colcnt loop
dbms_output.put_line('column ' || i
|| ' ' || l_desctab(i).col_name
|| ' type ' || l_desctab(i).col_type
|| ' length ' || l_desctab(i).col_max_len
);
end loop;
dbms_sql.close_cursor(l_curid);
end;
/
column 1 RPAD(ENAME,INSTR(ENAME,'')) type 1 length 4000
column 2 RPAD(ENAME,4) type 1 length 16
column 3 SUBSTR(ENAME,1,INSTR(ENAME,'')) type 1 length 40
As you can see, it knows the length for a fixed-length rpad and a substr (note the size is four times the actual string length due to the multibyte characterset), but falls back to the maximum for the rpad using a function.
What you're seeing is SQL*Plus showing a 4000-char column. If you did this in SQL Developer you would see the header for that column is indeed 4000 characters. SQL*Plus helps a bit by reducing the displayed column header to the line size, and wraps the next column onto a separate line.
lpad ('string', n [, 'string_pad')
rpad ('string', n [, 'string_pad')
string is left padded to length n with string_pad. If string_pad is ommited, a space will be used as default
rpad is similar, but pads right instead of left.
from http://www.adp-gmbh.ch/ora/sql/rpad.html
and here is good example for understanding
begin
for i in 1 .. 15 loop
dbms_output.put_line(
rpad('string', i) || '<'
);
end loop;
end;

simple parameter substitution in regexp_matches postgreSQL function

I have a table with a structure like this...
the_geom data
geom1 data1+3000||data2+1000||data3+222
geom2 data1+500||data2+900||data3+22232
I want to create a function that returns the records by user request.
Example: for data2, retrieve geom1,1000 and geom2, 900
Till now I created this function (see below) which works quite good but I am facing a parameter substitution problem... (you can see I am not able to substitute 'data2' for $1 in... BUT yes I can use $1 later
regexp_matches(t::text, E'(data2[\+])([0-9]+)'::text)::text)[2]::integer
MY FUNCTION
create or replace function get_counts(taxa varchar(100))
returns setof record
as $$
SELECT t2.counter,t2.the_geom
FROM (
SELECT (regexp_matches(t.data::text, E'(data2[\+])([0-9]+)'::text)::text)[2]::integer as counter,the_geom
from (select the_geom,data from simple_inpn2 where data ~ $1::text) as t
) t2
$$
language sql;
SELECT get_counts('data2') will work **but we should be able to make this substitution**:
regexp_matches(t::text, E'($1... instead of E'(data2....
I think its more a syntaxis issue, as the function execution gives no error, just interprets $1 as a string and gives no result.
thanks in advance,
A E'$1' is a string literal (using the escape string syntax) containing a dollar sign followed by a one. An unquoted $1 is the first parameter to your function. So this:
regexp_matches(t, E'($1[\+])([0-9]+)'))[2]::integer
as you've found, won't interpolate the $1 with the function's first parameter.
The regex is just a string, a string with an internal structure but still just a string. If you know that $1 will be a normal word then you could say:
regexp_matches(t, E'(' || $1 || E'[\+])([0-9]+)'))[2]::integer
to paste your strings together into a suitable regex. However, it is better to be a little paranoid, sooner or later someone is going to call your function with a string like 'ha ha (' so you should be prepared for it. The easiest way that I can think of to add an arbitrary string to a regex is to escape all the non-word characters:
-- Don't forget to escape the escaped escapes! Hence all the backslashes.
str := regexp_replace($1, E'(\\W)', E'\\\\\\1', 'g');
and then paste str into the regex as above:
regexp_matches(t, E'(' || str || E'[\+])([0-9]+)'))[2]::integer
or better, build the regex outside the regexp_matches to cut down on the nested parentheses:
re := E'(' || str || E'[\+])([0-9]+)';
-- ...
select regexp_matches(t, re)[2]::integer ...
PostgreSQL doesn't have Perl's \Q...\E and the (?q) metasyntax applies until the end of the regex so I can't think of any better way to paste an arbitrary string into the middle of a regex as a non-regex literal value than to escape everything and let PostgreSQL sort it out.
Using this technique, we can do things like:
=> do $$
declare
m text[];
s text;
r text;
begin
s = E'''{ha)?';
r = regexp_replace(s, E'(\\W)', E'\\\\\\1', 'g');
r = '(ha' || r || ')';
raise notice '%', r;
select regexp_matches(E'ha''{ha)?', r) into m;
raise notice '%', m[1];
end$$;
and get the expected
NOTICE: ha'{ha)?
output. But if you leave out the regexp_replace escaping step, you'll just get an
invalid regular expression: parentheses () not balanced
error.
As an aside, I don't think you need all that casting so I removed it. The regexes and escaping are noisy enough, there's no need to throw a bunch of colons into the mix. Also, I don't know what your standard_conforming_strings is set to or which version of PostgreSQL you're using so I've gone with E'' strings everywhere. You'll also want to switch your procedure to PL/pgSQL (language plpgsql) to make the escaping easier.

How do I parse a string in Oracle?

How can I parse the value of "request" in the following string in Oracle?
<!-- accountId="123" activity="add" request="add user" -->
The size and the position of the request is random.
You can use regular expressions to find this:
regexp_replace(str, '.*request="([^"]*)".*', '\1')
Use INSTR(givenstring, stringchartosearch,start_position) to find the position of 'request="' and to find the position of the closing '"'.
Then use substr(string, starting_position, length).
You'd use a combination of instr and substr
THIS EXAMPLE IS FOR EXAMPLE PURPOSES ONLY. DO NOT USE IT IN PRODUCTION CODE AS IT IS NOT VERY CLEAN.
substr(my_str,
-- find request=" then get index of next char.
instr(my_str, 'request="') + 9,
-- This is the second " after request. It does not allow for escapes
instr(substr(my_str,instr(my_str, 'request="')), 2))
Below is my tested variations from cwallenpoole and Craig. For the regexp - note that if "request=" does not exist, the result will be the entire string. user349433 was partly there too, a space before "request=" in the search works just as well:
SET serveroutput ON
DECLARE
l_string VARCHAR2(100) := '<!-- accountId="123" activity="add" request="add user" -->';
l_result_from_substr VARCHAR2(50);
l_result_from_regexp VARCHAR2(50);
BEGIN
SELECT SUBSTR(l_string, instr(l_string, 'request="') + 9, instr(SUBSTR(l_string,instr(l_string, 'request="')), '"', 2)-1),
regexp_replace(l_string, '.* request="([^"]*)".*', '\1')
INTO l_result_from_substr,
l_result_from_regexp
FROM dual;
dbms_output.put_line('Result from substr: '||l_result_from_substr);
dbms_output.put_line('Result from regexp: '||l_result_from_regexp);
END;
/
Please note the equal sign "=" does not necessarily have to come immediately after the request variable in the assignment. As such, it is not entirely correct to search for "request=". You should create a basic finite state machine using INSTR to first find "request", then find "=", ...

How to run REPLACE function in Oracle9i with strings larger than 4000 characters

I have the following block of PLSQL that succeeds when ln_length is 4000 characters or less but fails with "ORA-01460: unimplemented or unreasonable conversion requested" when ln_length is > 4000 characters.
The block is:
DECLARE
ls_string VARCHAR2(32767);
ls_temp VARCHAR2(32767);
ln_length NUMBER := 4000;
BEGIN
ls_string := '';
FOR i IN 1..ln_length LOOP
ls_string := ls_string || 'x';
END LOOP;
SELECT REPLACE(ls_string,'bob')
INTO ls_temp FROM dual;
END;
How would I write an equivalent piece of code that caters for strings up to 32k in length?
Don't have 9i to test with, but perhaps this will get around it:
replace:
SELECT REPLACE(ls_string,'bob')
INTO ls_temp FROM dual;
with:
ls_temp := REPLACE(ls_string,'bob');
The RDBMS engine only supports VARCHAR2's up to 4000 in length, while PL/SQL supports up to 32767. Avoid going to the database for the REPLACE operation (it's unnecessary anyway) and it seems to work (at least w/ 10g).