print pattern in PL/SQL - oracle

I want to print pattern like this, but it prints like second one?
*
* *
* * *
* * * *
* * * * *
enter image description here -- here is my script
*
* *
* * *
* * * *
* * * * *

Your code is fine:
BEGIN
FOR i IN 1 .. 5 LOOP
FOR j IN i .. 4 LOOP
DBMS_OUTPUT.PUT(' ');
END LOOP;
FOR j IN 1 .. i LOOP
DBMS_OUTPUT.PUT('* ');
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
END LOOP;
END;
/
It outputs:
*
* *
* * *
* * * *
* * * * *
fiddle
Whatever IDE you are using may be stripping the leading whitespace.

The output you've shown is a bit confusing, because if the first line is losing its leading whitespace then the rest of them should be too. But it depends on your client, as MTO said.
If you are using SQL*Plus (and similar) then you may just need to do:
set serveroutput on format wrapped

Related

Getting Sum Using PL/SQL In Optimized Way

I have the below PL/SQL block which would be converted to a function, this would be used very heavily, is there a better and efficient way to re-write in the most optimized way?
Appreciate any suggestions or insights.
DECLARE
ln_grand_total NUMBER;
ln_total NUMBER;
ln_final_total NUMBER;
CURSOR E1
IS
SELECT SUM (qty * price * rate)
INTO ln_total
FROM maximo.po_lines pl
JOIN maximo.po_headers ph ON pl.HEADER_ID = ph.HEADER_ID
WHERE ph.HEADER_ID = 0123;
BEGIN
OPEN E1;
FETCH E1 INTO ln_grand_total;
ln_final_total := ROUND (ln_grand_total, 2);
DBMS_OUTPUT.put_line (ROUND (ln_grand_total, 2));
CLOSE E1;
DBMS_OUTPUT.put_line ('ln_final_total --> ' || ln_final_total);
END;
/
You don't need a cursor for this:
DECLARE
ln_total NUMBER;
BEGIN
SELECT ROUND( SUM (qty * price * rate), 2 )
INTO ln_total
FROM maximo.po_lines pl
JOIN maximo.po_headers ph
ON pl.HEADER_ID = ph.HEADER_ID
WHERE ph.HEADER_ID = 0123;
DBMS_OUTPUT.put_line ('ln_final_total --> ' || ln_total);
END;
/
Indeed there's no problem with the logic, but change the style such as
if HEADER_ID is column of numeric type, then remove the preceding
zero of 0123, otherwise quote that as '0123'
INTO clause cannot be used for a cursor definition. Eg. get rid of
INTO ln_total. So remove that local variable
Convert SUM (qty * price * rate) within the query of the cursor to
ROUND(SUM (qty * price * rate),2). So, get rid of ln_final_total
local variable
Therefore, you can use the below code block
DECLARE
ln_grand_total NUMBER(10,2);
CURSOR E1 IS
SELECT ROUND( SUM(qty * price * rate), 2)
FROM maximo.po_lines pl
JOIN maximo.po_headers ph
ON pl.HEADER_ID = ph.HEADER_ID
WHERE ph.HEADER_ID = '0123';
BEGIN
OPEN E1;
FETCH E1
INTO ln_grand_total;
CLOSE E1;
DBMS_OUTPUT.PUT_LINE('ln_grand_total --> ' || ln_grand_total);
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;

Oracle PL/SQL: numeric or value error

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;

How can i make this better?

Below i have created 2 triggers that apply a discount, one uses a function while the other does not. Is there any other way to make this efficient/better?
CREATE OR REPLACE TRIGGER APPLY_DISCOUNT
BEFORE INSERT OR UPDATE OF INV_NO,C_NO ON INVOICE
FOR EACH ROW
DECLARE
CURSOR C_APPTMNT
IS
SELECT C_NO,COUNT(C_NO)
FROM APPOINTMENT GROUP BY C_NO;
V_C_NO APPOINTMENT.C_NO%TYPE;
VISIT NUMBER(2);
BEGIN
VISIT:=CNT_VISIT(:NEW.C_NO);
IF VISIT BETWEEN 2 AND 4
AND :NEW.C_NO = V_C_NO THEN
:NEW.BILL := :NEW.BILL * 0.9;
ELSIF VISIT BETWEEN 5 AND 8
AND :NEW.C_NO = V_C_NO THEN
:NEW.BILL := :NEW.BILL * 0.8;
ELSIF VISIT >=9 AND :NEW.C_NO = V_C_NO THEN:NEW.BILL := :NEW.BILL * 0.7;
ELSE DBMS_OUTPUT.PUT_LINE('no discount added');
END IF;
CLOSE C_APPTMNT;
END;
/
////////////////////////////////////////////////////////////////
CREATE OR REPLACE FUNCTION ADD_DISCOUNT(
I_C_NO INVOICE.C_NO%TYPE, I_BILL INVOICE.BILL%TYPE)
RETURN NUMBER
IS
V_BILL invoice.bill%type;
CURSOR C_APPTMNT
IS
SELECT C_NO,COUNT(C_NO)
FROM APPOINTMENT GROUP BY C_NO;
V_C_NO INVOICE.C_NO%TYPE;
VISIT NUMBER;
BEGIN
OPEN C_APPTMNT;
FETCH C_APPTMNT INTO V_C_NO,VISIT;
IF VISIT >=3
AND I_C_NO = V_C_NO THEN
V_BILL := I_BILL * 0.9;
ELSIF VISIT >=6
AND I_C_NO = V_C_NO THEN
V_BILL := I_BILL * 0.8;
ELSIF VISIT >=9 AND I_C_NO = V_C_NO THEN V_BILL := I_BILL * 0.7;
ELSE V_BILL:= I_BILL;
END IF;
CLOSE C_APPTMNT;
RETURN V_BILL;
END;
/
CREATE OR REPLACE TRIGGER DIS_BILL
BEFORE INSERT OR UPDATE OF INV_NO,C_NO ON INVOICE
FOR EACH ROW
DECLARE
BEGIN
:NEW.BILL:=ADD_DISCOUNT(:NEW.C_NO,:NEW.BILL);
END;
/
The second one is wrong. If a value is >= 9 it is also >=6 and >=3. Therefore, those elses will never be reached.
In the first one, you write output, but only if no discount was added. It feels like you just put that line there because it won't compile without it, but you can also add a line containing null; to make an empty statement block compiling.
There are more tricks to make this trigger faster. For one, you don't have to query all records, since you know the group. And you can do the calculation in the query, although that won't make it much faster.
Your trigger could look like this:
CREATE OR REPLACE TRIGGER APPLY_DISCOUNT
BEFORE INSERT OR UPDATE OF INV_NO, C_NO ON INVOICE
FOR EACH ROW
BEGIN
SELECT
CASE
WHEN COUNT(C_NO) >= 9 THEN 0.7
WHEN COUNT(C_NO) >= 6 THEN 0.8
WHEN COUNT(C_NO) >= 3 THEN 0.9
ELSE 1
END * :NEW.BILL
INTO
:NEW.BILL
FROM
APPOINTMENT
WHERE
C_NO = :NEW.C_NO;
END;
/
I think SELECT INTO :NEW.BILL should work, but if not, you could select it into a variable and then assign it to :NEW.BILL.

Calling an excel function from oracle forms

Can anyone suggest how I can use ole2 to perform an excel function (e.g. PMT()), from oracle forms and get back the result??
I created PL/SQL functions that will calculate the PMT function per the formula that is in MS Excel.
This first function doesn't factor in the future value, the second does.
/* No future value factor */
FUNCTION pmt (APR IN NUMBER /* Rate (APR) */,
pv IN NUMBER /* Loan amount */,
nper IN NUMBER /* number of payments */
) RETURN NUMBER IS /* periodic payment amount */
BEGIN
RETURN (APR / (1 - power((1 + APR),-nper)) * pv );
END pmt;
/* With future value factor */
FUNCTION pmt (APR IN NUMBER, /* Rate (APR) */
nper IN NUMBER, /* Number of payments */
pv IN NUMBER, /* present value */
fv IN NUMBER /*future value */
) RETURN NUMBER IS /* periodic payment amount */
calcpmt NUMBER := 0;
powercalc NUMBER:=0;
BEGIN
powercalc:= POWER(1+APR, nper);
RETURN APR / (powercalc - 1) * -(pv * powercalc + fv);
END;
I would just recreate the PMT function in PL/SQL, the native language of forms. E.g. based on http://forums.contractoruk.com/technical/28716-calculate-apr-loan-repayment-using-pl-sql-java.html:
CREATE
FUNCTION pmt (rate IN NUMBER /* Rate (APR) */
,amt IN NUMBER /* Loan amount */
,payments IN NUMBER /* number of payments */
) RETURN NUMBER IS /* periodic payment amount */
BEGIN
RETURN (rate/12*amt*power((1+rate/12),payments))/(power((1+rate/12),payments)-1);
END pmt;
e.g.
BEGIN
DBMS_OUTPUT.put_line(
'PMT = $' || TRUNC( pmt(0.249, 5000, 11), 2)
);
END;
/
PMT = $513.07

Resources