Oracle PL/SQL: numeric or value error - oracle

The problem I have is that in a loop I get the numeric or value error for using NUMBER's. The test data im using for LR_UPDATE_ROWS consists of 2 elements currently. Both are of the NUMBER type. The type of LR_UPDATE_ROWS itself is a PL/SQL table type, which consist of a NUMBER(3,0) column.
The code is as follows:
DBMS_OUTPUT.PUT_LINE(LR_UPDATED_ROWS.FIRST); /* Prints out 1 */
DBMS_OUTPUT.PUT_LINE(LR_UPDATED_ROWS.LAST); /* Prints out 2 */
a := LR_UPDATED_ROWS.FIRST; /* Assignment works */
b := LR_UPDATED_ROWS.LAST; /* Assignment works */
DBMS_OUTPUT.PUT_LINE(a); /* Prints out 1 */
DBMS_OUTPUT.PUT_LINE(b); /* Prints out 2 */
IF LR_UPDATED_ROWS IS NOT NULL THEN
IF LR_UPDATED_ROWS.FIRST = 1 AND LR_UPDATED_ROWS.LAST = 1 THEN
lv_rows_lst:=lv_rows_lst||','||LR_UPDATED_ROWS(1);
ELSE
FOR I IN LR_UPDATED_ROWS.FIRST..LR_UPDATED_ROWS.LAST
LOOP
lv_rows_lst:=lv_rows_lst||','||LR_UPDATED_ROWS(I);
END LOOP;
END IF;
lv_rows_lst:=SUBSTR(lv_rows_lst,2,LENGTH(lv_rows_lst));
OPEN LS_CUR FOR 'SELECT * FROM DOCUMENT_QUEUE DQ WHERE DQ.ENV_ID IN ('||lv_rows_lst||')';
ELSE
LS_CUR := LS_CUR;
END IF;
The row: „FOR I IN LR_UPDATED_ROWS.FIRST..LR_UPDATED_ROWS.LAST“ gives me the error:"PL/SQL: numeric or value error“.
All that my research from the web revealed about this error was that it was some sort of conversion or number size incompatibility error. Unfortunately I have been unable to understand in which way.
All help and hints are appreciated.

Try this.
DBMS_OUTPUT.PUT_LINE(LR_UPDATED_ROWS.FIRST);
/* Prints out 1 */
DBMS_OUTPUT.PUT_LINE(LR_UPDATED_ROWS.LAST);
/* Prints out 2 */
a := LR_UPDATED_ROWS.FIRST;
/* Assignment works */
b := LR_UPDATED_ROWS.LAST;
/* Assignment works */
DBMS_OUTPUT.PUT_LINE(a);
/* Prints out 1 */
DBMS_OUTPUT.PUT_LINE(b);
/* Prints out 2 */
IF LR_UPDATED_ROWS.EXISTS(1) THEN
/* Still not getting the use of this piece of code */
IF LR_UPDATED_ROWS.FIRST = 1 AND LR_UPDATED_ROWS.LAST = 1 THEN
lv_rows_lst :='SELECT COLUMN_VALUE FROM TABLE(LR_UPDATED_ROWS)';
ELSE
FOR I IN LR_UPDATED_ROWS.FIRST..LR_UPDATED_ROWS.LAST
LOOP
lv_rows_lst:=lv_rows_lst||','||LR_UPDATED_ROWS(I);
END LOOP;
END IF;
lv_rows_lst:=SUBSTR(lv_rows_lst,2,LENGTH(lv_rows_lst));
OPEN LS_CUR FOR 'SELECT * FROM DOCUMENT_QUEUE DQ WHERE DQ.ENV_ID IN ('||lv_rows_lst||')';
ELSE
LS_CUR := LS_CUR;
END IF;

Related

Count the day where 'CL' In oracle report what I tried is this :

Hi dear I want to count the CL from rows how many CL and Multiply it with this 827 what I tried is this its generating error what will be correct please
function CF_CLFormula return Number is
A NUMBER;
begin
IF :DAY_COUNT = 'CL'
THEN
A := COUNT(:DAY_COUNT)*827;
RETURN A;
END IF;
end;
it gives me error of count function is used only in select, yes it is but what I can use for this and get my answer
It won't work that way. You probably have to actually count rows from the table in a separate SELECT statement. Something like this:
function CF_CLFormula return Number is
A NUMBER;
begin
IF :DAY_COUNT = 'CL'
THEN
select count(*) * 827 --> this
into a
from some_table
where day_count = 'CL';
RETURN A;
END IF;
end;

oracle PL/SQL how to calculate range ip for IPv6 cidr

ex.IPv6 address with CIDR:
2620:0:2d0:200::7/32
out put
Start Range: 2620:0:0:0:0:0:0:0
End Range: 2620:0:ffff:ffff:ffff:ffff:ffff:ffff
how to calculate with PL/SQL ?
Once I wrote a general PL/SQL Package where you can do such conversions. It works for both, IPv4 and IPv6.
CREATE OR REPLACE PACKAGE IP_Util AS
/**
* Convert an IP-Address into decimal value.
* #param IP The IP-Address, e.g. '10.151.20.224' or '1080::8:800:200C:417A'.
* Supports also mixed notation like '0:0:0:0:0:FFFF:129.144.52.38'. CIDR value (e.g. '1080::8:800:200C:417A/80') is ignored.
* #return The decimal equivalent
*/
FUNCTION IP2Decimal(IP IN VARCHAR2) RETURN NUMBER DETERMINISTIC;
/**
* Convert an IP-Address into RWA value.
* #param IP The IP-Address, e.g. '10.151.20.224' or '1080::8:800:200C:417A'.
* Supports also mixed notation like '0:0:0:0:0:FFFF:129.144.52.38'. CIDR value (e.g. '1080::8:800:200C:417A/80') is ignored.
* #param ver IP version, either 4 or 6. If NULL then function determines the IP version.
* #return The RAW equivalent
*/
FUNCTION IP2RAW(IP IN VARCHAR2, ver IN INTEGER DEFAULT NULL) RETURN RAW DETERMINISTIC;
/**
* Convert an IP-Address from decimal value into IPv4 or IPv6 format.
* #param ip Decimal IP-Address, 0..(2**32)-1 or 0..(2**128)-1
* #param ver IP version, either 4 or 6
* #return The IP in IPv4 or IPv6 format
*/
FUNCTION Decimal2IP(ip IN NUMBER, ver IN INTEGER) RETURN VARCHAR2 DETERMINISTIC;
/**
* Convert an IP-Address from RAW value into IPv4 or IPv6 format.
* #param ip RAW value of IP-Address, 0..FFFFFFFF or 0..FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
* #param ver IP version, either 4 or 6
* #return The IP in IPv4 or IPv6 format
*/
FUNCTION RAW2IP(ip IN RAW, ver IN INTEGER) RETURN VARCHAR2 DETERMINISTIC;
/**
* Returns SubnetMask of given IP-Subnet in CIDR notation.
* #param Ip Subnet IP-Address with CIDR notation, e.g. '10.152.10.17/24' or '1080::8:800:200C:417A/60'
* #return SubnetMask Subnet mask of IP-Subnet, e.g. '255.255.255.0' or 'ffff:ffff:ffff::'
*/
FUNCTION SubnetMask(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC;
/**
* Returns Network prefix of given IP-Subnet. In IPv4 this address was called subnet address.
* #param Ip IP-Address of subnet, e.g. '10.152.10.17' or '1080:0:100:8:800:200C:FFFF:417A'
* #param SubnetMask Subnet mask of subnet, e.g. '255.255.0.0' or 'FFFF:FFFF:FFFF::'
* #return Network prefix, i.e. the first address from subnet, for example '10.152.0.0' or '1080:0:100:8:800:200C:FFFF::'
*/
FUNCTION NetworkPrefix(Ip IN VARCHAR2, SubnetMask IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC;
/**
* Returns Network prefix of given IP-Subnet. In IPv4 this address was called subnet address.
* #param Ip IP-Subnet with CIDR notation, e.g. '10.152.10.17/24' or '1080:0:100:8:800:200C:FFFF:417A/60'
* #return Network prefix, i.e. the first address from subnet, for example '10.152.0.0' or '1080:0:100:8:800:200C:FFFF::'
*/
FUNCTION NetworkPrefix(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC;
/**
* Returns Broadcast address of given IP-Subnet.
* IPv6 does not provide Broadcast anymore. However, function supports IPv6 for internal purpose.
* #param Ip IP-Address of subnet, e.g. '10.152.10.17' or '1080:0:100:8:800:200C:FFFF:417A'
* #param SubnetMask Subnet mask of subnet, e.g. '255.255.0.0' or 'FFFF:FFFF:FFFF::'
* #return Broadcast address, i.e. the last address from subnet, for example '10.152.10.255' or '1080:0:100:8:800:ffff:ffff:ffff'
*/
FUNCTION BroadcastIp(Ip IN VARCHAR2, SubnetMask IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC;
/**
* Returns Broadcast address of given IP-Subnet.
* IPv6 does not provide Broadcast anymore. However, function supports IPv6 for internal purpose.
* #param Ip IP-Subnet with CIDR notation, e.g. '10.152.10.17/24' or '1080:0:100:8:800:200C:FFFF:417A/60'
* #return Broadcast address, i.e. the last address from subnet, for example '10.152.10.255' or '1080:0:100:8:800:ffff:ffff:ffff'
*/
FUNCTION BroadcastIp(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC;
/**
* Translate Subnet mask to CIDR.
* #param SubnetMask Subnet mask of subnet, e.g. '255.255.0.0' or 'FFFF:FFFF:FFFF::'
* #return CIDR value, e.g. 26
*/
FUNCTION SubnetMask2CIDR(SubnetMask VARCHAR2) RETURN INTEGER RESULT_CACHE DETERMINISTIC;
/**
* Translate CIDR to Subnet mask in IPv4 or IPv6 format.
* #param CIDR Length of network prefix
* #param ver IP version, either 4 or 6
* #return Subnet mask, e.g. '255.255.0.0' or 'FFFF:FFFF:FFFF::'
*/
FUNCTION CIDR2SubnetMask(CIDR IN INTEGER, ver IN INTEGER) RETURN VARCHAR2 RESULT_CACHE DETERMINISTIC;
/**
* Returns full uncompressed IPv6 Address. Mainly used for internal purpose like conversion, storage, comparison, etc.
* '::' is replaced by zero pads, leading '0' are inserted (if leadingZero = TRUE), converted to lower cases.
* #param Ip Compact IPv6-Address (with CIDR or without CIDR, e.g. 2620:0:2D0:A2A2::7)
* #param leadingZero If TRUE then bit fields are padded with '0' in order to have always 4 characters
* #return The full IPv6 Address with 8 x 16 bits, e.g. '2620:0000:02d0:a2a2:0000:0000:0000:0007'
*/
FUNCTION UncompressIpV6(Ip IN VARCHAR2, leadingZero IN BOOLEAN DEFAULT TRUE) RETURN VARCHAR2 DETERMINISTIC;
/**
* Makes an canonical IPv6 address according to RFC 5952, i.e. human readable.
* #param IPv6 IPv6-Address (with or without '::', with or without leading '0')
* #return Canonical IPv6 Address, e.g. 2620:0:2d0:200::7
*/
FUNCTION Canonical_IPv6(IPv6 IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC;
END IP_Util;
/
CREATE OR REPLACE PACKAGE BODY IP_Util AS
NUMERIC_OVERFLOW EXCEPTION;
PRAGMA EXCEPTION_INIT(NUMERIC_OVERFLOW, -1426);
FUNCTION IP2Decimal(IP IN VARCHAR2) RETURN NUMBER DETERMINISTIC IS
DecimalIp NUMBER; -- INTEGER does not cover (2**128)-1
BEGIN
IF REGEXP_LIKE(IP, ':') THEN
-- IPv6 Address
IF REGEXP_LIKE(IP, '\d+\.\d+\.\d+\.\d+') THEN
-- Mixed notation, e.g.: 0:0:0:0:0:FFFF:129.144.52.38
SELECT SUM(TO_NUMBER(REGEXP_SUBSTR(UncompressIpV6(IP), '[[:xdigit:]]+', 1, LEVEL), 'XXXX') * POWER(65536, 8-LEVEL))
INTO DecimalIp
FROM dual
CONNECT BY LEVEL <= 6;
SELECT DecimalIp + SUM(REGEXP_SUBSTR(REGEXP_SUBSTR(UncompressIpV6(IP), '\d+\.\d+\.\d+\.\d+'), '\d+', 1, LEVEL) * POWER(256, 4-LEVEL))
INTO DecimalIp
FROM dual
CONNECT BY LEVEL <= 4;
RETURN DecimalIp;
ELSE
SELECT SUM(TO_NUMBER(REGEXP_SUBSTR(UncompressIpV6(IP), '[[:xdigit:]]+', 1, LEVEL), 'XXXX') * POWER(65536, 8-LEVEL))
INTO DecimalIp
FROM dual
CONNECT BY LEVEL <= 8;
RETURN DecimalIp;
END IF;
ELSE
-- IPv4 Address
SELECT SUM(REGEXP_SUBSTR(IP, '\d+', 1, LEVEL) * POWER(256, 4-LEVEL))
INTO DecimalIp
FROM dual
CONNECT BY LEVEL <= 4;
RETURN DecimalIp;
END IF;
END IP2Decimal;
FUNCTION IP2RAW(IP IN VARCHAR2, ver IN INTEGER DEFAULT NULL) RETURN RAW DETERMINISTIC IS
BEGIN
IF ver IS NULL THEN
IF REGEXP_LIKE(IP, ':') THEN
RETURN IP2RAW(IP, 6);
ELSE
RETURN IP2RAW(IP, 4);
END IF;
ELSE
IF ver = 6 THEN
RETURN HEXTORAW(LPAD(TO_CHAR(IP2Decimal(ip), 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'), 32, '0'));
ELSIF ver = 4 THEN
RETURN HEXTORAW(LPAD(TO_CHAR(IP2Decimal(ip), 'fmXXXXXXXX'), 8, '0'));
ELSE
RAISE VALUE_ERROR;
END IF;
END IF;
END IP2RAW;
FUNCTION RAW2IP(ip IN RAW, ver IN INTEGER) RETURN VARCHAR2 DETERMINISTIC IS
res VARCHAR2(45);
BEGIN
-- Range check "TO_NUMBER(ip, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') < 2**32, resp 2**128" not needed, because RAW values are usually not based on error-prone user input
IF ver = 4 THEN
-- Take only last 32 bit from RAW value with UTL_RAW.SUBSTR(ip, -4)
SELECT LISTAGG(TO_NUMBER(SUBSTR(SUBSTR(LPAD(RAWTOHEX(UTL_RAW.SUBSTR(ip, -4)), 8, '0'), -8), 2*LEVEL-1, 2), 'XX'), '.') WITHIN GROUP (ORDER BY LEVEL)
INTO res
FROM DUAL
CONNECT BY LEVEL <= 4;
RETURN res;
ELSIF ver = 6 THEN
RETURN Canonical_IPv6(SUBSTR(REGEXP_REPLACE(LPAD(RAWTOHEX(ip), 32, '0'), '([[:xdigit:]]{4})', ':\1'), 2));
ELSE
RAISE VALUE_ERROR;
END IF;
END RAW2IP;
FUNCTION Decimal2IP(ip IN NUMBER, ver IN INTEGER) RETURN VARCHAR2 DETERMINISTIC IS
res VARCHAR2(45);
BEGIN
IF ip IS NULL THEN
RETURN NULL;
END IF;
IF ver = 4 THEN
IF ip > 2**32 - 1 THEN
RAISE NUMERIC_OVERFLOW;
END IF;
SELECT LISTAGG(TO_NUMBER(SUBSTR(LPAD(TO_CHAR(ip, 'fmXXXXXXXX'), 8, '0'), 2*LEVEL-1, 2), 'XX'), '.') WITHIN GROUP (ORDER BY LEVEL)
INTO res
FROM dual
CONNECT BY LEVEL <= 4;
RETURN res;
ELSIF ver = 6 THEN
IF ip > 2**128 - 1 THEN
RAISE NUMERIC_OVERFLOW;
END IF;
res := LPAD(TO_CHAR(ip, 'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'),32, '0');
RETURN Canonical_IPv6(SUBSTR(REGEXP_REPLACE(res, '([[:xdigit:]]{4})', ':\1'), 2));
ELSE
RAISE VALUE_ERROR;
END IF;
END Decimal2IP;
FUNCTION SubnetMask(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
IF Ip IS NULL OR NOT REGEXP_LIKE(Ip, '/\d{1,3}$') THEN
RETURN NULL;
END IF;
IF REGEXP_LIKE(Ip, ':') THEN
RETURN CIDR2SubnetMask(REGEXP_SUBSTR(Ip, '\d{1,3}$'), 6);
ELSE
RETURN CIDR2SubnetMask(REGEXP_SUBSTR(Ip, '\d{1,2}$'), 4);
END IF;
END SubnetMask;
FUNCTION NetworkPrefix(Ip IN VARCHAR2, SubnetMask IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
IF REGEXP_LIKE(ip, ':') THEN
RETURN RAW2IP(UTL_RAW.BIT_AND(Ip2RAW(Ip, 6), Ip2RAW(SubnetMask, 6)), 6);
ELSE
RETURN RAW2IP(UTL_RAW.BIT_AND(Ip2RAW(Ip, 4),Ip2RAW(SubnetMask, 4)), 4);
END IF;
END NetworkPrefix;
FUNCTION NetworkPrefix(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
RETURN NetworkPrefix(REGEXP_REPLACE(Ip, '/\d{1,3}$'), SubnetMask(Ip));
END NetworkPrefix;
FUNCTION BroadcastIp(Ip IN VARCHAR2, SubnetMask IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
Subnet RAW(16);
SubnetInv RAW(16);
BEGIN
IF REGEXP_LIKE(ip, ':') THEN
Subnet := UTL_RAW.BIT_AND(Ip2RAW(Ip, 6), Ip2RAW(SubnetMask, 6));
SubnetInv := UTL_RAW.BIT_COMPLEMENT(Ip2RAW(SubnetMask, 6));
RETURN RAW2IP(UTL_RAW.BIT_OR(Subnet, SubnetInv), 6);
ELSE
Subnet := UTL_RAW.BIT_AND(Ip2RAW(Ip, 4), Ip2RAW(SubnetMask, 4));
SubnetInv := UTL_RAW.BIT_COMPLEMENT(Ip2RAW(SubnetMask, 4));
RETURN RAW2IP(UTL_RAW.BIT_OR(Subnet, SubnetInv), 4);
END IF;
END BroadcastIp;
FUNCTION BroadcastIp(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
RETURN BroadcastIp(REGEXP_REPLACE(Ip, '/\d{1,3}$'), SubnetMask(Ip));
END BroadcastIp;
FUNCTION SubnetMask2CIDR(SubnetMask VARCHAR2) RETURN INTEGER RESULT_CACHE DETERMINISTIC IS
ip RAW(16);
cidr INTEGER;
BEGIN
IF SubnetMask IS NULL THEN
RETURN NULL;
END IF;
IF REGEXP_LIKE(SubnetMask, ':') THEN
ip := IP2RAW(SubnetMask, 6);
cidr := 128-LOG(2, TO_NUMBER(UTL_RAW.BIT_COMPLEMENT(ip), 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')+1);
ELSE
ip := IP2RAW(SubnetMask, 4);
cidr := 32-LOG(2, TO_NUMBER(UTL_RAW.BIT_COMPLEMENT(ip), 'XXXXXXXX')+1);
END IF;
RETURN cidr;
END SubnetMask2CIDR;
FUNCTION CIDR2SubnetMask(CIDR IN INTEGER, ver IN INTEGER) RETURN VARCHAR2 RESULT_CACHE DETERMINISTIC IS
BEGIN
IF CIDR IS NULL THEN
RETURN NULL;
END IF;
IF ver = 4 THEN
IF CIDR NOT BETWEEN 0 AND 32 THEN
RAISE VALUE_ERROR;
END IF;
RETURN RAW2IP(UTL_RAW.BIT_COMPLEMENT(HEXTORAW(LPAD(TO_CHAR(2**(32-cidr)-1, 'fmXXXXXXXX'),8 , '0'))), 4);
ELSIF ver = 6 THEN
IF CIDR NOT BETWEEN 0 AND 128 THEN
RAISE VALUE_ERROR;
END IF;
RETURN RAW2IP(UTL_RAW.BIT_COMPLEMENT(HEXTORAW(LPAD(TO_CHAR(2**(128-cidr)-1, 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'),32 , '0'))), 6);
ELSE
RAISE VALUE_ERROR;
END IF;
END CIDR2SubnetMask;
FUNCTION UncompressIpV6(Ip IN VARCHAR2, leadingZero IN BOOLEAN DEFAULT TRUE) RETURN VARCHAR2 DETERMINISTIC IS
IpFull VARCHAR2(50);
len INTEGER := 7;
TYPE VARCHAR_TABLE_TYPE IS TABLE OF VARCHAR2(10);
BitFields VARCHAR_TABLE_TYPE;
cidr VARCHAR2(5);
BEGIN
IF NOT REGEXP_LIKE(Ip, ':') THEN
RETURN Ip;
END IF;
cidr := REGEXP_SUBSTR(Ip, '/\d{1,3}$');
IpFull := REGEXP_REPLACE(Ip, '/\d{1,3}$');
IF REGEXP_LIKE(IpFull, '::') THEN
IpFull := REGEXP_REPLACE(REGEXP_REPLACE(IpFull, '^::', '0::'), '::$', '::0');
IF REGEXP_LIKE(IpFull, ':\d+\.\d+\.\d+\.\d+') THEN
-- Mixed notation, e.g.: 2002::FFFF:129.144.52.38
len := 6;
END IF;
WHILE REGEXP_COUNT(IpFull, ':') <= len LOOP
IpFull := REGEXP_REPLACE(IpFull, '::', ':0::');
END LOOP;
IpFull := REGEXP_REPLACE(IpFull, '::', ':');
END IF;
IF NOT leadingZero THEN
RETURN LOWER(IpFull||cidr);
END IF;
SELECT REGEXP_SUBSTR(IpFull, '[^:]+', 1, LEVEL)
BULK COLLECT INTO BitFields
FROM dual
CONNECT BY REGEXP_SUBSTR(IpFull, '[^:]+', 1, LEVEL) IS NOT NULL;
IpFull := LPAD(BitFields(1), 4, '0');
FOR i IN 2..BitFields.COUNT LOOP
IF REGEXP_LIKE(BitFields(i), '\d+\.\d+\.\d+\.\d+') THEN
IpFull := IpFull ||':'||BitFields(i);
ELSE
IpFull := IpFull ||':'||LPAD(BitFields(i), 4, '0');
END IF;
END LOOP;
RETURN LOWER(IpFull)||cidr;
END UncompressIpV6;
FUNCTION Canonical_IPv6(IPv6 IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
res VARCHAR2(50);
cidr VARCHAR2(5);
BEGIN
IF NOT REGEXP_LIKE(IPv6, ':') THEN
RETURN IPv6;
ELSIF REGEXP_LIKE(IPv6, '::') THEN
-- Do not shorten twice
res := UncompressIpV6(IPv6, FALSE);
ELSE
-- RFC 5952 section-4.3
res := LOWER(IPv6);
END IF;
-- Split CIDR if existing
cidr := REGEXP_SUBSTR(res, '/\d{1,3}$');
res := REGEXP_REPLACE(res, '/\d{1,3}$');
-- remove leading '0', RFC 5952 section-4.1
res := REGEXP_REPLACE(res, '(:|^)0+([[:xdigit:]]+)', '\1\2');
WITH ip AS
-- split IP into 16-bit fields
(SELECT REGEXP_SUBSTR(res, '[^:]+', 1, LEVEL) AS val, LEVEL AS pos
FROM DUAL
CONNECT BY REGEXP_SUBSTR(res, '[^:]+', 1, LEVEL) IS NOT NULL),
p AS
-- find consecutive (at least 2) 0 fields, RFC 5952 section-4.2.2
(SELECT pos, len, match_num
FROM ip
MATCH_RECOGNIZE (
ORDER BY pos
MEASURES
FINAL COUNT(*) AS len,
MATCH_NUMBER() AS match_num
ALL ROWS PER MATCH
PATTERN(zero{2,})
DEFINE zero AS val = '0')
),
m AS
-- select longest run of consecutive 0 fields, RFC 5952 section-4.2.3
(SELECT * FROM p WHERE len = (SELECT MAX(len) FROM p)),
f AS
-- select first sequence of longest run of consecutive 0 fields, RFC 5952 section-4.2.3
(SELECT * FROM m WHERE match_num = (SELECT MIN(match_num) FROM m))
SELECT REGEXP_REPLACE(LISTAGG(NVL2(match_num, ':', val), ':') WITHIN GROUP (ORDER BY pos), ':{2,}', '::')
INTO res
FROM ip
LEFT OUTER JOIN f USING (pos);
RETURN res||cidr;
END Canonical_IPv6;
END IP_Util;
/
Then you can use it for example like this:
SELECT
IP_Util.NetworkPrefix('2620:0:2d0:200::7/32'),
IP_Util.BroadcastIp('2620:0:2d0:200::7/32')
FROM dual;
2620:: 2620:0:ffff:ffff:ffff:ffff:ffff:ffff
If you prefer 2620:0:0:0:0:0:0:0 then use
IP_Util.UncompressIpV6(IP_Util.NetworkPrefix('2620:0:2d0:200::7/32'), false)
However, according RFC 5952 2620:: would be the preferred format.
Here are a few examples how this package can be used:
-- Determine if (IPv4) Address is a Private IP:
CREATE OR REPLACE FUNCTION IsPrivate_IP(ip IN VARCHAR2) RETURN NUMBER DETERMINISTIC IS
BEGIN
IF IP_Util.NetworkPrefix('10.0.0.0', '255.0.0.0') = IP_Util.NetworkPrefix(ip, '255.0.0.0') THEN
RETURN 1;
ELSIF IP_Util.NetworkPrefix('172.16.0.0', '255.240.0.0') = IP_Util.NetworkPrefix(ip, '255.240.0.0') THEN
RETURN 1;
ELSIF IP_Util.NetworkPrefix('192.168.0.0', '255.255.0.0') = IP_Util.NetworkPrefix(ip, '255.255.0.0') THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END IsPrivate_IP;
Or a more complex one which translates an IPv4 into IPv6 or vice versa using 6to4 and 6RD Network Prefix:
CREATE OR REPLACE FUNCTION NAT64(ip IN VARCHAR2, IpV6mask IN VARCHAR2 DEFAULT '::ffff:0:0') RETURN VARCHAR2 DETERMINISTIC IS
shift INTEGER;
cidr INTEGER;
n NUMBER;
a RAW(16);
b RAW(16);
BEGIN
IF REGEXP_LIKE(ip, ':') THEN
-- Translate from IPv6 to IPv4
IF NOT REGEXP_LIKE(IpV6mask, '/\d+{1,3}$') THEN
RETURN IP_Util.RAW2IP(UTL_RAW.BIT_AND(IP_Util.IP2Raw(ip), HEXTORAW('000000000000000000000000FFFFFFFF')), 4);
ELSE
shift := 128 - REGEXP_SUBSTR(IpV6mask, '\d+{1,3}$');
IF shift < 32 THEN
RAISE VALUE_ERROR;
END IF;
-- Generate mask for IPv4 address, e.g. '0000000000000000FFFFFFFF00000000'
b := HEXTORAW(LPAD(TO_CHAR((2**shift-1) - (2**(shift-32)-1), 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'),32 , '0'));
n := TO_NUMBER(UTL_RAW.BIT_AND(IP_Util.IP2Raw(ip), b), 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
-- UTL_RAW.SUBSTR does not work because you can shift only Bytes, I need Bits
RETURN IP_Util.Decimal2IP(TRUNC(n / 2**(shift-32)), 4);
END IF;
ELSE
-- Translate from IPv4 to IPv6
IF NOT REGEXP_LIKE(IpV6mask, '/\d+{1,3}$') THEN
a := UTL_RAW.BIT_AND(IP_Util.IP2Raw(IpV6mask), UTL_RAW.BIT_COMPLEMENT(HEXTORAW(LPAD(TO_CHAR(2**32-1 , 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'),32 , '0'))));
RETURN IP_Util.RAW2IP(UTL_RAW.BIT_OR(a, IP_Util.IP2RAW(ip, 6)), 6);
ELSE
cidr := REGEXP_SUBSTR(IpV6mask, '\d+{1,3}$');
shift := 128 - 32 - cidr;
IF shift < 0 THEN
RAISE VALUE_ERROR;
END IF;
a := UTL_RAW.BIT_AND(IP_Util.IP2Raw(IpV6mask), UTL_RAW.BIT_COMPLEMENT(HEXTORAW(LPAD(TO_CHAR(2**(128-cidr)-1 , 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'),32 , '0'))));
b := HEXTORAW(LPAD(TO_CHAR(2**shift * IP_Util.IP2Decimal(ip), 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'),32 , '0'));
RETURN IP_Util.RAW2IP(UTL_RAW.BIT_OR(a, b), 6);
END IF;
END IF;
END NAT64;

How to find a dbms_output.put_line() alternative to print contents line by line every time when it gets called in every iteration?

I want to view the output as the program goes while processing some records. Reading the line will not help, as it just retrieves is from the buffer and nothing else. For example:
DECLARE
CURSOR cEmploee IS SELECT * FROM g_emploees;
iTotal INTEGER := 0;
iCount INTEGER := 0;
BEGIN
SELECT COUNT(*) FROM g_emploees INTO iTotal;
FOR rLine IN cEmploee loop
dbms_output.put_line('Porcessed['||rLine.id||']: '|| ((iCount/iTotal)*100) || '%')
iCount := iCount + 1;
END LOOP;
END;
I cannot use dbms_output.get_line(), So stop marking it answered !
I cannot pipe the output to a file for read-only reasons !
Is there a command/setting for DBMS that I can use in order to view the processed % and print the line for processed in EVERY ITERATION and not at the end as a whole bunch of lines persisting in the buffer (The line printed must show every and exact time in PL/SQL when "dbms_output.put_line" is called not like 500 lines at the end of the execution) ??
CREATE OR REPLACE FUNCTION test_pipe
RETURN sys.DBMS_DEBUG_VC2COLL
pipelined
as
CURSOR cEmploee IS
SELECT * FROM g_emploees;
iTotal INTEGER := 0;
iCount INTEGER := 0;
BEGIN
SELECT COUNT(*)
INTO iTotal
FROM g_emploees ;
FOR rLine IN cEmploee loop
PIPE row('Porcessed['||rLine.id||']: '|| ((iCount/iTotal)*100) || '%');
iCount := iCount + 1;
END LOOP;
END;
/
--execute below statements ON command window :
SQL >set arraysize 1
SQL > SELECT * FROM TABLE(test_pipe);

How to get the declared size of a varchar2 in oracle database

Trying to get the size of a defined variable in Oracle. I may need to use a number when declaring the size of a varchar2 but would rather not have to keep track of an extra variable or number.
example pseudo code:
declare
myvar varchar(42) := 'a';
begin
/* I know the length is length(myvar) = 1. */
/* but how do I get 42? */
/* What is the max defined size of this variable */
declared_size_of(myvar);
end
The reason I need this is to lpad the length of the string to the declared size so it doesn't generate an exception.
As #Justin said in his comments, you don't have to explicitly blank pad the string if you use CHAR data type. Oracle would blank-pad the value to it's maximum size.
From documentation,
If the data type of the receiver is CHAR, PL/SQL blank-pads the value
to the maximum size. Information about trailing blanks in the original
value is lost.
For example,
SQL> SET serveroutput ON
SQL> DECLARE
2 myvar CHAR(42);
3 BEGIN
4 myvar:='a';
5 dbms_output.put_line(LENGTH(myvar));
6 END;
7 /
42
PL/SQL procedure successfully completed.
SQL>
Brute Force technique using exception handling which is probably very inefficient:
DECLARE
myvar varchar2(42) := 'a'; /* using varchar */
v_size number := null;
x varchar(4000) := '';
v_length number := 0;
BEGIN
begin
v_length := length(myvar);
x := myvar;
FOR i in v_length..8001 LOOP
myvar := myvar || ' '; /* add one space at a time until it causes an exception */
End Loop;
EXCEPTION
-- WHEN NO_DATA_FOUND THEN
WHEN OTHERS THEN
v_length := length(myvar);
end;
dbms_output.put_line('Declared size is varchar('||v_length
||') and length(myvar) is '||length(trim(myvar)));
END;
To fetch the max. of a column input, you simply could do:
SELECT MAX(LENGTH(Column))
FROM TableA;

How do I determine if a PL/SQL parameter value was defaulted?

Suppose I have a PL/SQL stored procedure as follows:
PROCEDURE do_something(foo VARCHAR2 DEFAULT NULL) IS
BEGIN
/* Do something */
END;
Now, suppose do_something is invoked two different ways:
/* Scenario 1: The 'foo' parameter defaults to NULL */
do_something();
/* Scenario 2: The 'foo' parameter is explicitly set to NULL */
do_something(foo => NULL)
How can I define the do_something procedure to determine which scenario is calling it?
Edit: Clarifying my intentions for this procedure:
FUNCTION find_customer(name VARCHAR2 DEFAULT NULL, number VARCHAR2 DEFAULT NULL) RETURN NUMBER IS
BEGIN
/* Query the "customer" table using only those parameters provided */
END;
Below are example uses of this procedure with the associated SQL clauses desired:
/* SELECT * FROM customer WHERE customer.name = 'Sam' */
find_customer(name => 'Sam')
/* SELECT * FROM customer WHERE customer.name = 'Sam' AND customer.number = '1588Z' */
find_customer(name => 'Sam', number => '1588Z')
/* SELECT * FROM customer WHERE customer.name = 'Sam' AND customer.number IS NULL */
find_customer(name => 'Sam', number => NULL)
/* SELECT * FROM customer WHERE customer.name IS NULL */
find_customer(name => NULL)
/* SELECT * FROM customer WHERE customer.name IS NULL AND customer.number IS NULL */
find_customer(name => NULL, number => NULL)
How about instead of defaulting to null, default the omitted parameter values to something you will never use in the real world? The values you use should belong to some domain so choose values outside that domain.
eg
PROCEDURE do_something(foo VARCHAR2 DEFAULT '*##') IS
l_foo VARCHAR2(32000); -- local copy of foo parm
BEGIN
IF foo = '*##' THEN
-- I know the parm was omitted
l_foo := NULL;
ELSE
l_foo := foo;
END IF;
END;
You could overload the procedure instead of using a default value:
PROCEDURE do_something(foo VARCHAR2) IS
BEGIN
/* Do something */
END;
PROCEDURE do_something IS
BEGIN
/* here you know: no argument. Then call do_something(null) */
END;

Resources