Scalar UDF expression table-troubleshoot - user-defined-functions

Why calling return me:
Msg 208, Level 16, State 1, Line 1
Invalid object name 'udf_string'.
When call look like this:
select *
from [database].[udf_string]('Lorem ipsum dolor sit amet', ' ', 3)
UDF code look like this:
alter FUNCTION [dbo].[udf_string]
(
#start_str varchar(130),
#split_str varchar(130),
#element_index int
)
RETURNS varchar(130)
AS
BEGIN
declare #final_str varchar(130)
select #final_str = concat_ws('',a_split.t_val ,'')
from (
SELECT value as t_val ,
ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS str_num
FROM STRING_SPLIT(#start_str, #split_str)
) a_split
where a_split.str_num = #element_index
return #final_str
END

My bad, query should be look like:
select [database].[udf_string]('Lorem ipsum dolor sit amet', ' ', 3)
Because this is not table function.

Related

Not getting multiple data for binding parameters in select statement in oracle [duplicate]

I have this query that I'm passing 2 parameters, COUNTRY_REGION parameter and COST_CENTER parameter
I have the possibility to pass both parameters at the same time COST_CENTER and COUNTRY_REGION..... Or pass one or the other... This part is OK.
You can see in the first image below
SELECT
dwg.GEOGRAPHY_ID as geographyId
,INITCAP (lower (dwc.COUNTRY_REGION)) as countryRegion
,INITCAP (lower (dwc.COUNTRY_NAME)) as countryName
,dp.PROJECT_ID as projectId
FROM
DATALAKE.DWL_GEOGRAPHIES dwg
,DATALAKE.DWB_PROJECT dp
,DATALAKE.DWL_GEOGRAPHY_COUNTRIES dwgc
,DATALAKE.DWL_COUNTRY dwc
,DATALAKE.DWB_PROJECT_FINANCIAL dpf
,DATALAKE.DWL_GOLIVE dgl
where dwg.geography_id = dp.project_geography_id
and dwg.geography_id = dwgc.geography_id
and dwc.country_id = dwgc.country_id
and dp.PROJECT_ID = dpf.PROJECT_ID
and dpf.PROJECT_ID = dgl.PROJECT_ID
and dpf.FLAG_ACTIVE = 1
and ((dp.cost_center = (:costCenter) and INITCAP (lower (dwc.COUNTRY_REGION)) = (:countryRegion))
or (:costCenter IS null and INITCAP (lower (dwc.COUNTRY_REGION)) = (:countryRegion))
or (dp.cost_center = (:costCenter) and :countryRegion IS null)
)
order by dwc.COUNTRY_REGION
But I WANT TO HAVE THE OPTION TO PASSA TWO OR MORE IN THE SAME PARAMETER as in the image below...
example:
COUNTRY_REGION: Peru, Chile, Argentina
or
COST_CENTER : 10500, 1000, ... , ....
I would like help, I've tried several things and I can't proceed, thank you very much.
You cannot pass multiple values with a single bind variable.
What you can do is pass in a single string that contains a delimited list and match a sub-string of the list to the value:
SELECT *
FROM table_name
WHERE ', ' || :country_region_list || ', ' LIKE '%, ' || country_region || ', %'
OR ', ' || :cost_centre_list || ', ' LIKE '%, ' || cost_centre || ', %'
Which would make your query:
SELECT dwg.GEOGRAPHY_ID as geographyId
, INITCAP(dwc.COUNTRY_REGION) as countryRegion
, INITCAP(dwc.COUNTRY_NAME) as countryName
, dp.PROJECT_ID as projectId
FROM DATALAKE.DWL_GEOGRAPHIES dwg
INNER JOIN DATALAKE.DWB_PROJECT dp
ON (dwg.geography_id = dp.project_geography_id)
INNER JOIN DATALAKE.DWL_GEOGRAPHY_COUNTRIES dwgc
ON (dwg.geography_id = dwgc.geography_id)
INNER JOIN DATALAKE.DWL_COUNTRY dwc
ON (dwc.country_id = dwgc.country_id)
INNER JOIN DATALAKE.DWB_PROJECT_FINANCIAL dpf
ON (dp.PROJECT_ID = dpf.PROJECT_ID)
INNER JOIN DATALAKE.DWL_GOLIVE dgl
ON (dpf.PROJECT_ID = dgl.PROJECT_ID)
WHERE dpf.FLAG_ACTIVE = 1
AND (
', ' || :costCenter || ', ' LIKE '%, ' || dp.cost_center || ', %'
OR :costCenter IS null
)
AND (
', ' || :countryRegion || ', '
LIKE '%, ' || INITCAP(dwc.COUNTRY_REGION) || ', %'
OR :countryRegion IS null
)
AND (:costCenter IS NOT NULL OR :countryRegion IS NOT NULL)
order by dwc.COUNTRY_REGION

How to modify column data-type while column is in used

I have problem while I use SELECT query. Unfortunettly, the ID is store as VARCHAR which is big mistake and right now I have problem in following function
FUNCTION GET_SUB_PROJECTS(p_currentUserId IN VARCHAR,p_projectId IN INT)
RETURN SYS_REFCURSOR IS
rc SYS_REFCURSOR;
-- getSubProject
BEGIN
OPEN rc FOR
SELECT
p.*,
a.number_ AS activityNumber,
a.description AS activityDescription
FROM
projects p
LEFT JOIN
project_users_schedule_dates pusd
ON
pusd.ProjectID = p.ProjectID AND pusd.UserID = p_currentUserId
LEFT JOIN
activities a
ON
a.id = p.activity
LEFT JOIN
responsible_persons rp
ON
rp.ProjectID = p.ProjectID AND rp.UserID = p_currentUserId
LEFT JOIN
users u
ON
u.UserID = p_currentUserId
WHERE
(u.User_roleID = 1 AND
p.CustomName LIKE CONCAT((SELECT CustomName FROM projects pr WHERE pr.ProjectID = p_projectId), '%') AND p.ProjectID <> p_projectId)
OR
((
(p.Responsible_person_id = p_currentUserId OR p.Delivery_contact = p_currentUserId OR rp.UserID = p_currentUserId OR (pusd.UserID = p_currentUserId AND SYSTIMESTAMP BETWEEN TO_DATE(pusd.StartDate,'YYYY-MM-DD') AND TO_DATE(pusd.EndDate,'YYYY-MM-DD') + INTERVAL '1' DAY AND
SYSTIMESTAMP BETWEEN TO_DATE(p.StartDate,'YYYY-MM-DD') AND TO_DATE(p.EndDate,'YYYY-MM-DD') + INTERVAL '1' DAY))
)
AND
p.CustomName LIKE CONCAT((SELECT CustomName FROM projects pr WHERE pr.ProjectID = p_projectId), '%') AND p.ProjectID <> p_projectId)
ORDER BY p.CustomName;
RETURN rc;
END GET_SUB_PROJECTS;
When I call function it needs to return data, but it doesn't. Somehow, here p.Responsible_person_id and p.Delivery_contact needs to be NUMBER but somehow it is VARCHAR
When I call function I use
SELECT PROJECT_PACKAGE.GET_SUB_PROJECTS('199',141) FROM DUAL
I found one solution to modify but It throw me error like
Error report -
ORA-01439: column to be modified must be empty to change datatype
01439. 00000 - "column to be modified must be empty to change datatype"
What to do in this situation ? What is the best method to solve this issue ?
You can change the data type of a column online using dbms_redefinition
create table t (
c1 varchar2(10)
primary key
);
create table t_new (
c1 number(10, 0)
primary key
);
insert into t values ( '1.0000' );
commit;
begin
dbms_redefinition.start_redef_table (
user, 't', 't_new',
col_mapping => 'to_number ( c1 ) c1',
options_flag => dbms_redefinition.cons_use_rowid
);
end;
/
exec dbms_redefinition.sync_interim_table ( user, 't', 't_new' );
exec dbms_redefinition.finish_redef_table ( user, 't', 't_new' );
desc t
Name Null? Type
C1 NOT NULL NUMBER(10)
select * from t;
C1
1
There are also options to copy constraints, triggers, indexes, etc. automatically in this process.

Re-writing Query

Overall Task :- I need to retrieve data from 45 fields in system A and dump that data into a temp table which is then picked up by a unix process which produces an xml data file to be imported into system B.
Specific Question : What would be the best way of retrieving the data to be written into the 45 fields. Majority of the data is independent and can't be retrieved using a single statement. The way i currently retrieve this data is as follows (example below)
My temp tables hold the affected properties ID that i need to extract data for. i.e PROP_LIST_TEMP and ASSOC_PROP_TEMP.
SELECT SUBSTR (pro.pro_propref, 1, 25) UPRN,
(SELECT SUBSTR (adr_building, 1, 100)
FROM addresses, address_usages
WHERE aus_adr_refno = adr_refno
AND aus_aut_far_code = 'PHYSICAL'
AND aus_aut_fao_code = 'PRO'
AND (aus_end_date IS NULL OR aus_end_date > SYSDATE)
AND aus_pro_refno = pro.pro_refno)
BUILDING_NAME,
(SELECT CASE
WHEN (adr_street_number like 'BLOC%'
OR adr_street_number like '%-%'
OR adr_street_number like '%/%')
THEN NULL
ELSE regexp_replace (adr_street_number, '[^[:digit:]]+')
END
FROM addresses, address_usages
WHERE aus_adr_refno = adr_refno
AND aus_aut_far_code = 'PHYSICAL'
AND aus_aut_fao_code = 'PRO'
AND (aus_end_date IS NULL OR aus_end_date > SYSDATE)
AND aus_pro_refno = pro.pro_refno)
STREET_NUMBER,
(SELECT CASE
WHEN (adr_street_number like 'BLOC%'
OR adr_street_number like '%-%'
OR adr_street_number like '%/%')
THEN SUBSTR (adr_street_number, 1, 20)
ELSE REGEXP_REPLACE (adr_street_number, '[^[:alpha:]]+', '')
END
FROM addresses, address_usages
WHERE aus_adr_refno = adr_refno
AND aus_aut_far_code = 'PHYSICAL'
AND aus_aut_fao_code = 'PRO'
AND (aus_end_date IS NULL OR aus_end_date > SYSDATE)
AND aus_pro_refno = pro.pro_refno)
STREET_NUMBER_SUFFIX,
(SELECT SUBSTR (ptv_pty_code, 1, 3)
FROM prop_type_values
WHERE ptv_refno = pro.pro_hou_ptv_refno)
HOUSE_TYPE
FROM properties pro
WHERE pro_refno IN (select * from PIMSS_PROP_LIST_TEMP
UNION
select * from PIMSS_ASSOC_PROP_TEMP)
AND pro.pro_hou_hrv_hot_code IN
(SELECT frv_code
FROM first_ref_values
WHERE frv_frd_domain IN ('ASS_OWN_REF')
AND frv_current_ind = 'Y');
Since the where clauses of the subqueries in the select statement are identical, you could simply pull that out into the where clause, like so:
SELECT SUBSTR (pro.pro_propref, 1, 25) UPRN,
SUBSTR (addr.adr_building, 1, 100) BUILDING_NAME,
CASE WHEN (addr.adr_street_number like 'BLOC%'
OR addr.adr_street_number like '%-%'
OR addr.adr_street_number like '%/%')
THEN NULL
ELSE regexp_replace (addr.adr_street_number, '[^[:digit:]]+')
END STREET_NUMBER,
CASE WHEN (addr.adr_street_number like 'BLOC%'
OR addr.adr_street_number like '%-%'
OR addr.adr_street_number like '%/%')
THEN SUBSTR (addr.adr_street_number, 1, 20)
ELSE REGEXP_REPLACE (addr.adr_street_number, '[^[:alpha:]]+', '')
END STREET_NUMBER_SUFFIX,
(SELECT SUBSTR (ptv_pty_code, 1, 3)
FROM prop_type_values
WHERE ptv_refno = pro.pro_hou_ptv_refno) HOUSE_TYPE
FROM properties pro,
(select adr_building,
adr_street_number
FROM addresses, address_usages
WHERE aus_adr_refno = adr_refno
AND aus_aut_far_code = 'PHYSICAL'
AND aus_aut_fao_code = 'PRO'
AND (aus_end_date IS NULL OR aus_end_date > SYSDATE)) addr
WHERE pro.pro_refno = aus_pro_refno
and pro_refno IN (select * from PIMSS_PROP_LIST_TEMP
UNION
select * from PIMSS_ASSOC_PROP_TEMP)
AND pro.pro_hou_hrv_hot_code IN (SELECT frv_code
FROM first_ref_values
WHERE frv_frd_domain IN ('ASS_OWN_REF')
AND frv_current_ind = 'Y');
You might possibly need an outer join if there's a chance that no rows could be returned from the addr subquery.

How to return all rows if IN clause has no value?

Following is sample query.
CREATE PROCEDURE GetModel
(
#brandids varchar(100), -- brandid="1,2,3"
#bodystyleid varchar(100) -- bodystyleid="1,2,3"
)
AS
select * from model
where brandid in (#brandids) -- use a UDF to return table for comma delimited string
and bodystyleid in (#bodystyleid)
My requirement is that if #brandids or #bodystyleid is blank, query should return all rows for that condition.
Please guide me how to do this? Also suggest how to write this query to optimize performance.
You'll need dynamic SQL or a split function for this anyway, since IN ('1,2,3') is not the same as IN (1,2,3).
Split function:
CREATE FUNCTION dbo.SplitInts
(
#List VARCHAR(MAX),
#Delimiter CHAR(1)
)
RETURNS TABLE
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM (
SELECT Item = x.i.value('(./text())[1]', 'int') FROM (
SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.') ) AS a CROSS APPLY [XML].nodes('i') AS x(i)) AS y
WHERE Item IS NOT NULL
);
Code becomes something like:
SELECT m.col1, m.col2 FROM dbo.model AS m
LEFT OUTER JOIN dbo.SplitInts(NULLIF(#brandids, ''), ',') AS br
ON m.brandid = COALESCE(br.Item, m.brandid)
LEFT OUTER JOIN dbo.SplitInts(NULLIF(#bodystyleid, ''), ',') AS bs
ON m.bodystyleid = COALESCE(bs.Item, m.bodystyleid)
WHERE (NULLIF(#brandids, '') IS NULL OR br.Item IS NOT NULL)
AND (NULLIF(#bodystyleid, '') IS NULL OR bs.Item IS NOT NULL);
(Note that I added a lot of NULLIF handling here... if these parameters don't have a value, you should be passing NULL, not "blank".)
Dynamic SQL, which will have much less chance of leading to bad plans due to parameter sniffing, would be:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT columns FROM dbo.model
WHERE 1 = 1 '
+ COALESCE(' AND brandid IN (' + #brandids + ')', '')
+ COALESCE(' AND bodystyleid IN (' + #bodystyleid + ')', '');
EXEC sp_executesql #sql;
Of course as #JamieCee points out, dynamic SQL could be vulnerable to injection, as you'll discover if you search for dynamic SQL anywhere. So if you don't trust your input, you'll want to guard against potential injection attacks. Just like you would if you were assembling ad hoc SQL inside your application code.
When you move to SQL Server 2008 or better, you should look at table-valued parameters (example here).
if(#brandids = '' or #brandids is null)
Begin
Set #brandids = 'brandid'
End
if(#bodystyleid = '' or #bodystyleid is null)
Begin
Set #bodystyleid = 'bodystyleid'
End
Exec('select * from model where brandid in (' + #brandids + ')
and bodystyleid in (' + #bodystyleid + ')')

How to insert rows using cursor in Oracle 11g

I am trying to write a function in oracle which will use cursor to insert data in one of the table. We need select query to pick the data which needs to be inserted. This is the first cursor I am writing and it turned to be too complex.
My cursor is as below:
/* Formatted on 11/5/2011 11:26:57 AM (QP5 v5.149.1003.31008) */
DECLARE
CURSOR csgetpgmecultstrecrefrs (
update_date DATE,
sequence_type VARCHAR2,
pip_number VARCHAR2,
startfrom INT,
endon INT)
IS
SELECT /*+first_rows(25) parallel (PE,20) */
pecu.component,
pecu.component_serial_no,
TO_DATE ('11/03/2011 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
date_received,
TO_DATE ('11/03/2011 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
date_programmed,
pecu.date_requested,
pecu.component_model_no,
pecu.product_type,
pecu.product_model_no,
pecu.product_serial_no,
pecu.factory_source,
pecu.programming_organization,
pecu.programming_site,
pecu.program_version,
pecu.ecu_serial_no,
pecu.ecu_part_no,
pecu.ecu_level,
pecu.software_assembly_id,
jdcp_pip_swa.pip_version software_assembly_id_upgrade,
TO_DATE ('11/03/2011 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
software_upgrade_date,
jdcp_pip_details.released_by software_upgraded_by,
pecu.power_bump,
pecu.fuel_system_part_no,
pecu.fuel_pump_serial_no,
pecu.rack_slope,
pecu.off_set,
pecu.ecu_hours,
pecu.cal_file,
pecu.ecu_boot_block_part_no,
jdcp_pip_details.released_by user_id,
pecu.performance_option_part_no,
pecu.vehicle_option_part_no,
'PIP' sequence_type,
pecu.flex_power_part_no,
pecu.performance_option_cd,
pecu.vehicle_option_cd,
pecu.lineage,
pecu.replaced_by_esn,
pecu.replaces_esn,
pecu.esn_copied_from,
pecu.payload_seq_no,
pecu.vehicle_system_id,
pecu.user_account,
pecu.ecu_opcode_part_no,
pecu.opcode_compat_code,
pecu.marked_qa
FROM ( ( jdcp_pip_details
INNER JOIN
jdcp_pip_pin_assc
ON jdcp_pip_details.pip_number =
jdcp_pip_pin_assc.pip_number)
INNER JOIN
jdcp_pip_swa
ON jdcp_pip_details.pip_swa_id = jdcp_pip_swa.pip_swa_id)
INNER JOIN
( (SELECT pe.component,
pe.component_serial_no,
pe.display_serial_no_13,
pe.display_serial_no_17,
pe.date_requested,
pe.component_model_no,
pe.product_type,
pe.product_model_no,
pe.product_serial_no,
pe.factory_source,
pe.programming_organization,
pe.programming_site,
pe.program_version,
pe.ecu_serial_no,
pe.ecu_part_no,
pe.ecu_level,
pe.software_assembly_id,
pe.power_bump,
pe.fuel_system_part_no,
pe.fuel_pump_serial_no,
pe.rack_slope,
pe.off_set,
pe.ecu_hours,
pe.cal_file,
pe.ecu_boot_block_part_no,
pe.performance_option_part_no,
pe.vehicle_option_part_no,
pe.flex_power_part_no,
pe.performance_option_cd,
pe.vehicle_option_cd,
pe.lineage,
pe.replaced_by_esn,
pe.replaces_esn,
pe.esn_copied_from,
pe.payload_seq_no,
pe.vehicle_system_id,
pe.user_account,
pe.ecu_opcode_part_no,
pe.opcode_compat_code,
pe.marked_qa
FROM programmed_ecu_13_17_map_view pe
WHERE pe.date_received =
(SELECT /*+ INDEX_DESC(PEDR PROGRAMMED_ECU_INDEX8) */
pedr.date_received AS date_received
FROM programmed_ecu pedr
WHERE pedr.component_serial_no =
pe.component_serial_no
AND pedr.component = pe.component
AND (pedr.date_programmed) =
(SELECT /*+ INDEX_DESC(PEDP PROGRAMMED_ECU_INDEX8) */
pedp.date_programmed
FROM programmed_ecu pedp
WHERE pedp.
component_serial_no =
pedr.
component_serial_no
AND pedp.component =
pedr.component
AND ROWNUM = 1)
AND ROWNUM = 1)) pecu
INNER JOIN
software_assembly_id
ON pecu.vehicle_system_id =
software_assembly_id.vehicle_system_id)
ON (pecu.component = jdcp_pip_pin_assc.controller_short_name)
AND (jdcp_pip_swa.pip_version =
software_assembly_id.software_assembly_id)
AND (pecu.component =
software_assembly_id.controller_short_name)
WHERE (pecu.display_serial_no_13 = jdcp_pip_pin_assc.pin_number
OR pecu.display_serial_no_17 = jdcp_pip_pin_assc.pin_number)
AND pecu.software_assembly_id <> jdcp_pip_swa.pip_version
AND jdcp_pip_details.pip_number = 'TEST_FWD_ASSC'
AND jdcp_pip_pin_assc.status_cd NOT IN
('UC', 'SU', 'FA', 'RP', 'EC')
AND jdcp_pip_pin_assc.forward_associated = 'N'
AND ROWNUM BETWEEN 1 AND 25;
rc csgetpgmecultstrecrefrs%ROWTYPE;
BEGIN
OPEN csgetpgmecultstrecrefrs (update_date date,
sequence_type varchar2,
pip_number varchar2,
startfrom int,
endon int);
LOOP
FETCH csgetpgmecultstrecrefrs BULK COLLECT INTO rc;
EXIT WHEN csgetpgmecultstrecrefrs%NOTFOUND;
INSERT
INTO programmed_ecu (component,
component_serial_no,
date_received,
date_programmed,
date_requested,
component_model_no,
product_type,
product_model_no,
product_serial_no,
factory_source,
programming_organization,
programming_site,
program_version,
ecu_serial_no,
ecu_part_no,
ecu_level,
software_assembly_id,
software_assembly_id_upgrade,
software_upgrade_date,
software_upgraded_by,
power_bump,
fuel_system_part_no,
fuel_pump_serial_no,
rack_slope,
off_set,
ecu_hours,
cal_file,
ecu_boot_block_part_no,
user_id,
performance_option_part_no,
vehicle_option_part_no,
sequence_type,
flex_power_part_no,
performance_option_cd,
vehicle_option_cd,
lineage,
replaced_by_esn,
replaces_esn,
esn_copied_from,
payload_seq_no,
vehicle_system_id,
user_account,
ecu_opcode_part_no,
opcode_compat_code,
marked_qa
)
VALUES (
rc.component,
rc.component_serial_no,
rc.date_received,
rc.date_programmed,
rc.date_requested,
rc.component_model_no,
rc.product_type,
rc.product_model_no,
rc.product_serial_no,
rc.factory_source,
rc.programming_organization,
rc.programming_site,
rc.program_version,
rc.ecu_serial_no,
rc.ecu_part_no,
rc.ecu_level,
rc.software_assembly_id,
rc.software_assembly_id_upgrade,
rc.software_upgrade_date,
rc.software_upgraded_by,
rc.power_bump,
rc.fuel_system_part_no,
rc.fuel_pump_serial_no,
rc.rack_slope,
rc.off_set,
rc.ecu_hours,
rc.cal_file,
rc.ecu_boot_block_part_no,
rc.user_id,
rc.performance_option_part_no,
rc.vehicle_option_part_no,
rc.sequence_type,
rc.flex_power_part_no,
rc.performance_option_cd,
rc.vehicle_option_cd,
rc.lineage,
rc.replaced_by_esn,
rc.replaces_esn,
rc.esn_copied_from,
rc.payload_seq_no,
rc.vehicle_system_id,
rc.user_account,
rc.ecu_opcode_part_no,
rc.opcode_compat_code,
rc.marked_qa);
END LOOP;
COMMIT;
END;
Any help is appreciated. Thanks in advance !!!
Error message I am getting is:
Error at line 2
ORA-06550: line 147, column 44:
PLS-00103: Encountered the symbol "DATE" when expecting one of the following:
. ( ) , * # % & | = - + < / > at in is mod remainder not
range rem => .. <> or != or ~= >= <= <>
and or like LIKE2_ LIKE4_ LIKEC_ as between from using ||
multiset member SUBMULTISET_
ORA-06550: line 151, column 21:
PLS-00103: Encountered the symbol ")" when expecting one of the following:
, from into bulk
ORA-06550: line 254, column 4:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
end not pragma final instantiable order overriding static
member constructor map
Script Terminated on line 2."
The declaration of your cursor is incorrect. A cursor is not declared using data types, you need to remove the whole part between the brackets. The data types for each column are determined by the columns returned by the SELECT statement:
CURSOR csgetpgmecultstrecrefrs
IS
SELECT .....
See the examples in the manual for details:
http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/sqloperations.htm#sthref1296

Resources