MINI MINI MANI MO
Rem
Rem $Header: sdo/admin/sdorttz.sql /main/9 2017/10/20 11:01:24 rjanders Exp $
Rem
Rem sdorttz.sql
Rem
Rem Copyright (c) 2016, 2017, Oracle and/or its affiliates.
Rem All rights reserved.
Rem
Rem NAME
Rem sdorttz.sql - Router timezone create package
Rem
Rem DESCRIPTION
Rem For the SDO_TIMEZONES table (source of the timezones polygons)
Rem - Add the tables metadata to the USER_SDO_GEOM_METADATA table
Rem - Build a spatial index on the tables geometry field
Rem Build the ROUTER_TIMEZONES table (the Routers timezone user data)
Rem
Rem NOTES
Rem It is assumed that the SDO_ROUTER_LOG directory exists and is writable
Rem from PLSQL in the excuting schema. Users can run
Rem sdo_router_partition.validate_sdo_router_log_dir to be sure
Rem
Rem All logging is done to the sdo_router_timezones.log file in the
Rem SDO_ROUTER_LOG_DIR directory. The file name can be changed from
Rem the default in the calls, the directory can not.
Rem
Rem BEGIN SQL_FILE_METADATA
Rem SQL_SOURCE_FILE: sdo/admin/sdorttz.sql
Rem SQL_SHIPPED_FILE:
Rem SQL_PHASE:
Rem SQL_STARTUP_MODE: NORMAL
Rem SQL_IGNORABLE_ERRORS: NONE
Rem SQL_CALLING_FILE:
Rem END SQL_FILE_METADATA
Rem
Rem MODIFIED (MM/DD/YY)
Rem rjanders 10/08/17 - Add MDSYS to spatial type
Rem rjanders 06/30/17 - Add SYS/MDSYS prefixes
Rem rjanders 04/25/17 - Remove 'set echo on' directive
Rem mhorhamm 03/09/17 - Move is_simple_file_name to sdo_utl
Rem begeorge 02/16/17 - bug 25513512
Rem sravada 01/11/17 - bug 25370681
Rem cfreiwal 04/04/16 - Router timezone user data creation package
Rem
Rem ********************************************************************
Rem Indicate that this is an Oracle-Supplied object
@@?/rdbms/admin/sqlsessstart.sql
Rem ********************************************************************
-- Create the timezones generation package
--
CREATE OR REPLACE PACKAGE MDSYS.SDO_ROUTER_TIMEZONE AUTHID current_user AS
PROCEDURE cleanup_timezones;
PROCEDURE create_router_timezones_edges(log_file_name IN VARCHAR2 := 'sdo_router_timezones.log');
PROCEDURE create_sdo_timezones_index(log_file_name IN VARCHAR2 := 'sdo_router_timezones.log');
END SDO_ROUTER_TIMEZONE;
/
CREATE OR REPLACE PACKAGE BODY MDSYS.SDO_ROUTER_TIMEZONE AS
---------- Start logging section
-- Timezone log file
tz_log_file utl_file.file_type := NULL;
schema_name VARCHAR2(260) := NULL;
JAVA_ERROR EXCEPTION;
PARAMETER_ERROR EXCEPTION;
---
PROCEDURE log_message(message IN VARCHAR2, show_time IN BOOLEAN DEFAULT TRUE)
IS
BEGIN
-- No logfile, return
IF (utl_file.is_open(tz_log_file) = FALSE ) THEN
RETURN;
END IF;
IF (show_time) THEN
utl_file.put_line (tz_log_file, sdo_util.number_to_char(sysdate,'Dy fmMon DD HH24:MI:SS YYYY'));
END IF;
utl_file.put_line (tz_log_file, message);
utl_file.fflush(tz_log_file);
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20002, '[ERROR] Writing timezones log file');
END log_message;
---
FUNCTION open_log_file(log_file_name IN VARCHAR2)
RETURN VARCHAR2 AS
full_file_name VARCHAR2(256);
stmt VARCHAR2(256);
BEGIN
BEGIN
if (sdo_util.is_simple_file_name(log_file_name) = 'FALSE') then
raise_application_error(-20020, '[ERROR] bad file name');
end if;
-- Open (append) the Router timezones log file
IF (NOT utl_file.is_open(tz_log_file)) THEN
tz_log_file := utl_file.fopen ('SDO_ROUTER_LOG_DIR', log_file_name, 'A');
END IF;
stmt := 'SELECT directory_path FROM SYS.all_directories
WHERE directory_name=''SDO_ROUTER_LOG_DIR''';
EXECUTE IMMEDIATE stmt INTO full_file_name;
-- Make sure the path is terminated with a /
IF (instr(full_file_name, '/', length(full_file_name)) = 0)
THEN full_file_name := full_file_name || '/';
END IF;
full_file_name := full_file_name || log_file_name;
EXCEPTION
WHEN utl_file.invalid_path THEN
raise_application_error(-20006, '[ERROR] SDO_ROUTER_LOG_DIR directory not found');
WHEN utl_file.invalid_operation THEN
raise_application_error(-20006, '[ERROR] Bad directory path specified for SDO_ROUTER_LOG_DIR directory');
WHEN OTHERS THEN
raise_application_error(-20001, '[ERROR] Could not open log file');
END;
RETURN full_file_name;
END open_log_file;
---------- End logging section
---------- Start utility section
--- Add metadata to USER_SDO_GEOM_METADATA
---
PROCEDURE add_metadata(table_name IN VARCHAR2)
IS
l_table_name VARCHAR(256);
stmt VARCHAR2(256);
no NUMBER := 0;
BEGIN
l_table_name := nls_upper(SYS.DBMS_ASSERT.SIMPLE_SQL_NAME(table_name));
-- If the metadata already exists, drop it so it can be recreated
stmt := 'SELECT COUNT(*) FROM mdsys.user_sdo_geom_metadata WHERE table_name = :name';
EXECUTE IMMEDIATE stmt into no using l_table_name;
IF (no = 1) THEN
stmt := 'DELETE FROM mdsys.user_sdo_geom_metadata WHERE table_name = :name';
EXECUTE IMMEDIATE stmt using l_table_name;
log_message('[INFO] Dropped metadata for ' || table_name ||
' from mdsys.user_sdo_geom_metadata');
END IF;
-- Add the metadata
stmt := 'INSERT INTO mdsys.user_sdo_geom_metadata ' ||
'(table_name, column_name, diminfo, srid) ' ||
'VALUES(' ||
':tname, ' ||
'''GEOMETRY'', ' ||
'MDSYS.SDO_DIM_ARRAY(' ||
'MDSYS.SDO_DIM_ELEMENT(''Long'', -180, 180, 1), ' ||
'MDSYS.SDO_DIM_ELEMENT(''Lat'', -90, 90, 1)), ' ||
'8307)';
EXECUTE IMMEDIATE stmt using l_table_name;
COMMIT;
log_message('[INFO] Added metadata for ' || table_name ||
' to mdsys.user_sdo_geom_metadata');
EXCEPTION
WHEN OTHERS THEN
log_message(SQLERRM);
raise_application_error(-20101,
'[ERROR] While generating geometry metadata for ' ||
l_table_name);
END add_metadata;
---
FUNCTION index_exists(index_name IN VARCHAR2)
RETURN VARCHAR2
IS
stmt VARCHAR2(256);
no NUMBER := 0;
BEGIN
stmt := 'SELECT COUNT(*) FROM IND WHERE INDEX_NAME = :name';
EXECUTE IMMEDIATE stmt into no using nls_upper(index_name);
IF (no = 1) THEN
RETURN 'TRUE';
ELSE
RETURN 'FALSE';
END IF;
END index_exists;
---
FUNCTION metadata_exists(table_name IN VARCHAR2)
RETURN VARCHAR2
IS
stmt VARCHAR2(256);
no NUMBER := 0;
BEGIN
stmt := 'SELECT COUNT(*) FROM mdsys.user_sdo_geom_metadata WHERE table_name = :name';
EXECUTE IMMEDIATE stmt into no using nls_upper(table_name);
IF (no = 1) THEN
RETURN 'TRUE';
ELSE
RETURN 'FALSE';
END IF;
END metadata_exists;
---
FUNCTION table_exists(tab_name IN VARCHAR2)
RETURN VARCHAR2
IS
stmt VARCHAR2(256);
no NUMBER := 0;
BEGIN
stmt := 'SELECT COUNT(*) FROM TAB WHERE TNAME = :name';
EXECUTE IMMEDIATE stmt into no using nls_upper(tab_name);
IF (no = 1) THEN
RETURN 'TRUE';
ELSE
RETURN 'FALSE';
END IF;
END table_exists;
--
PROCEDURE clean_tables (all_tables IN BOOLEAN DEFAULT TRUE)
IS
BEGIN
IF (table_exists('router_timezones_nodes') = 'TRUE') THEN
EXECUTE IMMEDIATE 'DROP TABLE router_timezones_nodes';
END IF;
IF (table_exists('router_timezones_nodes_ins') = 'TRUE') THEN
EXECUTE IMMEDIATE 'DROP TABLE router_timezones_nodes_ins';
END IF;
IF (table_exists('router_timezones_orphan_nodes') = 'TRUE') THEN
EXECUTE IMMEDIATE 'DROP TABLE router_timezones_orphan_nodes';
END IF;
IF (all_tables) THEN
IF (table_exists('router_timezones_edges') = 'TRUE') THEN
EXECUTE IMMEDIATE 'DROP TABLE router_timezones_edges';
END IF;
END IF;
END clean_tables;
-- Make sure all of the edges in the edge table are in a timezone
PROCEDURE validate_edges_table
IS
stmt VARCHAR2(256);
edges NUMBER := 0;
tz_edges NUMBER := 0;
BEGIN
stmt := 'SELECT COUNT(edge_id) FROM router_timezones_edges';
EXECUTE IMMEDIATE stmt into tz_edges;
stmt := 'SELECT COUNT(edge_id) FROM edge';
EXECUTE IMMEDIATE stmt into edges;
IF (tz_edges != edges) THEN
raise_application_error(-20102, '[ERROR] Timezones edge table validation failed.');
END IF;
END validate_edges_table;
-- Make sure all of the nodes in the node table are in a timezone
PROCEDURE validate_nodes_table
IS
stmt VARCHAR2(256);
nodes NUMBER := 0;
tz_nodes NUMBER := 0;
BEGIN
stmt := 'SELECT COUNT(node_id) FROM router_timezones_nodes';
EXECUTE IMMEDIATE stmt into tz_nodes;
stmt := 'SELECT COUNT(node_id) FROM node';
EXECUTE IMMEDIATE stmt into nodes;
IF (tz_nodes != nodes) THEN
raise_application_error(-20103, '[ERROR] Timezones node table validation failed.');
END IF;
END validate_nodes_table;
---------- End utility section
---------- Start public API section
--- Cleanup temporary timezones tables
PROCEDURE cleanup_timezones
IS
BEGIN
clean_tables(FALSE);
END cleanup_timezones;
--- Create the raw timezones data needed by the user data generation in sdo_router_partition
PROCEDURE create_router_timezones_edges(log_file_name IN VARCHAR2 := 'sdo_router_timezones.log')
IS
full_file_name VARCHAR2(256);
schema_name VARCHAR2(130):= sys_context('userenv', 'CURRENT_SCHEMA');
stmt VARCHAR2(512);
BEGIN
full_file_name := open_log_file(log_file_name);
log_message('******** Begin generation of router_timezones_edges (timezones raw data)');
log_message('** Logfile location: ' || full_file_name, FALSE);
log_message('[INFO] Creating router_timezones_edges table for ' || schema_name);
-- Make sure the raw timezones data exists. This it the TZ_WORLD timezone
-- database with the shapefiles converted to SDO_GEOMETRYs. This table must
-- be imported into the Router schema from the Router/demo directory
IF (table_exists('SDO_TIMEZONES') = 'FALSE' ) THEN
raise_application_error(-20104, '[ERROR] Table not found: sdo_timezones');
END IF;
IF (metadata_exists('SDO_TIMEZONES') = 'FALSE' ) THEN
raise_application_error(-20105, '[ERROR] Spatial metadata not found for: sdo_timezones');
END IF;
IF (index_exists('SDO_TIMEZONES_GEOM_INDEX') = 'FALSE' ) THEN
raise_application_error(-20106, '[ERROR] Spatial index not found for: sdo_timezones');
END IF;
-- Cleanup any stray temporary tables, for both nodes and edges
clean_tables(TRUE);
-- First pass, associate most of the nodes with a timezone polygon
log_message('[INFO] Associate nodes to timezones');
stmt := 'CREATE TABLE router_timezones_nodes PARALLEL 4 NOLOGGING AS ' ||
' SELECT /*+ PARALLEL(node 4) */ n.node_id, t.tzid, n.geometry ' ||
' FROM sdo_timezones t, node n ' ||
' WHERE SDO_RELATE(n.geometry, t.geometry, ''MASK=ANYINTERACT'')=''TRUE''';
EXECUTE IMMEDIATE stmt;
-- Add geometry metadata
add_metadata('router_timezones_nodes');
-- Create indexes on the node_id and geometry columns
log_message('[INFO] Creating node id index on the router_timezones_nodes table');
stmt := 'CREATE INDEX rtzn_nid_idx ON router_timezones_nodes(node_id) PARALLEL 4';
EXECUTE IMMEDIATE stmt;
log_message('[INFO] Creating spatial index on the router_timezones_nodes table');
stmt := 'CREATE INDEX rtzn_geom_idx ON router_timezones_nodes(geometry) ' ||
'INDEXTYPE IS mdsys.spatial_index PARALLEL 4';
EXECUTE IMMEDIATE stmt;
-- Create the orphan nodes table for nodes that had no interaction with
-- a timezone polygon
stmt := 'CREATE TABLE router_timezones_orphan_nodes AS ' ||
' SELECT /*+ PARALLEL(node 4) */ node_id, geometry ' ||
' FROM node ' ||
' WHERE node_id NOT IN ' ||
' (SELECT /*+ PARALLEL(router_timezones_nodes 4) */ node_id ' ||
' FROM router_timezones_nodes)';
EXECUTE IMMEDIATE stmt;
log_message('[INFO] Associate orphan nodes to timezone polygons');
stmt := 'CREATE TABLE router_timezones_nodes_ins AS '||
' SELECT /*+ index(n rtzn_geom_idx) */ o.node_id, n.tzid, o.geometry '||
' FROM router_timezones_orphan_nodes o, router_timezones_nodes n ' ||
' WHERE sdo_nn(n.geometry, o.geometry, ''sdo_num_res=1 unit=meter'', 1) = ''TRUE''';
EXECUTE IMMEDIATE stmt;
stmt := 'INSERT /*+ APPEND */ INTO router_timezones_nodes ' ||
' SELECT * FROM router_timezones_nodes_ins';
EXECUTE IMMEDIATE stmt;
COMMIT;
-- Duplicate nodes show up when a node is located in two timezone polygons
-- that overlap. Not a frequent occurance but it happens.
log_message('[INFO] Duplicate node cleanup');
stmt := 'DELETE FROM router_timezones_nodes WHERE rowid NOT IN ' ||
' (SELECT MAX(rowid) FROM router_timezones_nodes GROUP BY node_id)';
EXECUTE IMMEDIATE stmt;
COMMIT;
-- Make sure all nodes are associated with a timezone
validate_nodes_table;
-- Create the final router_timezones_edges table which will drive the timezones
-- user data generation in the router_parition package.
log_message('[INFO] Associate edges to timezones');
-- Positive edge ids, use the timezone of the start node
stmt := 'CREATE TABLE router_timezones_edges NOLOGGING PARALLEL 4 AS ' ||
' SELECT e.edge_id, e.partition_id, n.tzid ' ||
' FROM edge e, router_timezones_nodes n ' ||
' WHERE edge_id>0 AND e.start_node_id=n.node_id';
EXECUTE IMMEDIATE stmt;
-- Negative edge ids, use the timezone of the end node
stmt := 'INSERT /*+ APPEND */ INTO router_timezones_edges ' ||
' SELECT e.edge_id, e.partition_id, n.tzid ' ||
' FROM edge e, router_timezones_nodes n ' ||
' WHERE edge_id<0 AND e.end_node_id=n.node_id';
EXECUTE IMMEDIATE stmt;
COMMIT;
-- Reasoning, now both directions of a two way edge are in the same timezone
log_message('[INFO] Creating edge id index on the router_timezones_edges table');
stmt := 'CREATE INDEX rte_eid_idx ON router_timezones_edges(edge_id) PARALLEL 4';
EXECUTE IMMEDIATE stmt;
-- Make sure all edges are associated with a timezone
validate_edges_table;
log_message('[INFO] Creating partition id index on the router_timezones_edges table');
stmt := 'CREATE INDEX rte_pid_idx ON router_timezones_edges(partition_id) PARALLEL 4';
EXECUTE IMMEDIATE stmt;
log_message('[INFO] Creating timezone id index on the router_timezones_edges table');
stmt := 'CREATE INDEX rte_tzid_idx ON router_timezones_edges(tzid) PARALLEL 4';
EXECUTE IMMEDIATE stmt;
-- Clean up the nodes tables but leave the edges table for the partitioning package
clean_tables(FALSE);
log_message('******** Completed generation of router_timezones_edges');
-- Close the log file
utl_file.fclose(tz_log_file);
EXCEPTION
WHEN OTHERS THEN
log_message(SQLERRM);
utl_file.fclose(tz_log_file);
raise_application_error(-20107, 'Creation of the timezones edges table failed');
END create_router_timezones_edges;
--- Spatial index creation on the sdo_timezones table
PROCEDURE create_sdo_timezones_index(log_file_name IN VARCHAR2 := 'sdo_router_timezones.log')
IS
full_file_name VARCHAR2(256);
schema_name VARCHAR2(130):= sys_context('userenv', 'CURRENT_SCHEMA');
BEGIN
full_file_name := open_log_file(log_file_name);
log_message('******** Begin indexing of the sdo_timezones table');
log_message('** Logfile location: ' || full_file_name, FALSE);
log_message('[INFO] Creating metadata and spatial index on ' ||
'sdo_timezones for ' || schema_name);
IF (table_exists('SDO_TIMEZONES') = 'FALSE' ) THEN
raise_application_error(-20107, '[ERROR] Table not found: sdo_timezones');
END IF;
-- Add metadata for the geometry column
add_metadata('sdo_timezones');
IF (index_exists('sdo_timezones_geom_index') = 'TRUE') THEN
EXECUTE IMMEDIATE 'DROP INDEX sdo_timezones_geom_index';
END IF;
-- Create the spatial index on the sdo_timezones table
EXECUTE IMMEDIATE 'CREATE INDEX sdo_timezones_geom_index ON sdo_timezones(geometry) ' ||
' INDEXTYPE IS mdsys.spatial_index PARALLEL 4';
-- If there is no spatial index on the node table then build one
IF ((index_exists('node_geometry_index') = 'FALSE') AND
(index_exists('node_geom_idx') = 'FALSE'))
THEN
log_message('[INFO] Rebuilding the spatial index on node table ');
-- Add geometry metadata
add_metadata('node');
EXECUTE IMMEDIATE 'CREATE INDEX node_geometry_index ON node(geometry) ' ||
' INDEXTYPE IS mdsys.spatial_index PARALLEL 4';
END IF;
EXCEPTION
WHEN OTHERS THEN
log_message(SQLERRM);
utl_file.fclose(tz_log_file);
raise_application_error(-20100, 'Indexing on the sdo_timezones table failed');
END create_sdo_timezones_index;
---------- End public API section
END SDO_ROUTER_TIMEZONE;
/
show errors;
grant execute on SDO_ROUTER_TIMEZONE to public;
create or replace public synonym SDO_ROUTER_TIMEZONE for
MDSYS.SDO_ROUTER_TIMEZONE;
commit;
Rem ********************************************************************
Rem Indicate this is an Oracle-Supplied object
@?/rdbms/admin/sqlsessend.sql
Rem ********************************************************************
OHA YOOOO