The reader is encouraged to browse through all the diagrams first to get a sense for what DMV is good for, and then make a second pass to study the mechanisms used to create them.
DMV is based on the LURQL metadata query language, so that link is required reading for understanding the details; it also covers the FEM metadata model used in the examples here.
farrago/examples/dmv/test.sql
),
with the domain being, um, a travel agency. The table and view
definitions are only intended to simulate meaningful dependencies at
table-level and schema-level; the actual details of the definitions
are bogus.
create schema accounts;
create table accounts.customers(customer_id int not null primary key);
create table accounts.addresses(address_id int not null primary key);
create view accounts.customer_addresses
as select * from accounts.customers, accounts.addresses;
create schema car_rentals;
create table car_rentals.cars(car_id int not null primary key);
create table car_rentals.contracts(contract_id int not null primary key);
create view car_rentals.customer_rentals as
select * from accounts.customers, car_rentals.contracts, car_rentals.cars;
create schema lodging;
create table lodging.hotels(hotel_id int not null primary key);
create table lodging.cabins(cabin_id int not null primary key);
create view lodging.locations as
select * from lodging.hotels
union all
select * from lodging.cabins;
create view lodging.registrations as
select * from accounts.customers, lodging.locations;
create schema billing;
create view billing.events as
select * from car_rentals.customer_rentals, lodging.registrations;
create view billing.all_addresses as
select * from accounts.addresses, lodging.locations;
create schema dmv_test;
create procedure dmv_test.dmv_render_graphviz(
foreign_server_name varchar(128),
lurql_filename varchar(1024),
transformation_filename varchar(1024),
dot_filename varchar(1024))
language java
no sql
external name 'class net.sf.farrago.test.DmvTestUdr.renderGraphviz';
The DDL above registers the Graphviz transformation procedure, making
it callable from SQL. The procedure takes four input parameters:
call dmv_test.dmv_render_graphviz(
null,
'${FARRAGO_HOME}/examples/dmv/schemaDependencies.lurql',
'${FARRAGO_HOME}/examples/dmv/schemaDependencies.xml',
'${FARRAGO_HOME}/examples/dmv/results/schemaDependencies.dot');
Before looking at the input files, view the resulting .dot file using
Graphviz to see what came out. On Linux, use the following command
after first installing GraphViz:
cd farrago/examples/dmv/results
dot -Tpng schemaDependencies.dot > schemaDependencies.png
Then open the .png file in a web browser. (Or if you have ImageMagick
installed, use a command like dot -Tpng schemaDependencies.dot |
display
to view the .dot file directly.) You should see this:
schemaDependencies.lurql
:
select *
from class LocalSchema
where name in ('ACCOUNTS', 'CAR_RENTALS', 'LODGING', 'BILLING') then (
follow composite forward destination class ColumnSet then (
follow origin end client
)
);
This query starts with the schemas of interest, collects the tables
and views contained by those schemas, and also retrieves dependencies
of which those objects are clients. However, it does not explicitly
retrieve the suppliers of those dependencies. The reason is that we
only want to visualize the dependencies between the schemas of
interest (instead of dragging in other schemas such as system schemas).
The result of that query is then transformed into a dependency graph
using the rules in schemaDependencies.xml
:
<DmvTransformationRuleSet>
<SetAllByAggregation
requestedKind="composite"
mapping="CONTRACTION"/>
<SetAllByAggregation
requestedKind="none"
mapping="COPY"/>
<SetByAssoc
assoc="DependencyClient"
mapping="CONTRACTION"/>
</DmvTransformationRuleSet>
Here's the interpretation:
CONTRACTION
. For
example, the two views EVENTS and ALL_ADDRESSES are both composite
children of the BILLING schema, so the corresponding vertices are all
rolled together into one vertex, with the outermost composite (schema
BILLING) serving as the representative for all of them.
COPY
) as edges in the
dependency graph. This includes the client and supplier associations
of CwmDependency, which is what gives the resulting diagram the
desired connectivity (after rolling them up to the schema level).
DependencyClient
is to be treated as a
CONTRACTION
rather than a COPY
. This is
actually superfluous because in FEM, each Dependency
object already has a composite association with the client
(ElementOwnership
) in addition to the non-composite
ClientDependency
. But it illustrates how to override
the settings for a particular association, and it is necessary
for subsequent examples to work correctly when the mapping for
composite associations is changed.
call dmv_test.dmv_render_graphviz(
null,
'${FARRAGO_HOME}/examples/dmv/schemaDependencies.lurql',
'${FARRAGO_HOME}/examples/dmv/objectDependencies.xml',
'${FARRAGO_HOME}/examples/dmv/results/objectDependenciesGrouped.dot');
objectDependencies.xml
is almost the same
as schemaDependencies.xml
, except that the mapping for
composite associations has been changed to HIERARCHY
instead of CONTRACTION
. This means that rather than
rolling up the dependencies, the composite container is converted into a
grouping construct in the dependency graph.
call dmv_test.dmv_render_graphviz(
null,
'${FARRAGO_HOME}/examples/dmv/objectDependencies.lurql',
'${FARRAGO_HOME}/examples/dmv/objectDependencies.xml',
'${FARRAGO_HOME}/examples/dmv/results/objectDependencies.dot');
select o, d
from class LocalSchema
where name in ('ACCOUNTS', 'CAR_RENTALS', 'LODGING', 'BILLING') then (
follow composite forward destination class ColumnSet as o then (
follow origin end client as d
)
);
The only difference is that this one omits the schemas from the results
(so the HIERARCHY mapping is ignored as irrelevant).
call dmv_test.dmv_render_graphviz(
null,
'${FARRAGO_HOME}/examples/dmv/schemaDependencies.lurql',
'${FARRAGO_HOME}/examples/dmv/viewsFloating.xml',
'${FARRAGO_HOME}/examples/dmv/results/viewsFloating.dot');
viewsFloating.xml
by adding an
additional rule to objectDependencies.xml
:
<DmvTransformationRuleSet>
<SetAllByAggregation
requestedKind="composite"
mapping="HIERARCHY"/>
<SetAllByAggregation
requestedKind="none"
mapping="COPY"/>
<SetByAssoc
assoc="DependencyClient"
mapping="CONTRACTION"/>
<SetByAssoc
assoc="ElementOwnership"
targetClass="LocalView"
mapping="REMOVAL"/>
</DmvTransformationRuleSet>
The last rule says that when the child of an
ElementOwnership
association is a LocalView
,
delete the corresponding edge entirely (REMOVAL
). One
side-effect is that the parent schema BILLING is left in the diagram
as a dangling vertex (upper right). Either DMV could be enhanced to
express the corresponding vertex removal, or else this situation
has to be handled via post-processing.
call dmv_test.dmv_render_graphviz(
null,
'${FARRAGO_HOME}/examples/dmv/carRentalsOnly.lurql',
'${FARRAGO_HOME}/examples/dmv/objectDependencies.xml',
'${FARRAGO_HOME}/examples/dmv/results/carRentalsOnly.dot');
call dmv_test.dmv_render_graphviz(
null,
'${FARRAGO_HOME}/examples/dmv/carRentalsPlusPeriphery.lurql',
'${FARRAGO_HOME}/examples/dmv/objectDependencies.xml',
'${FARRAGO_HOME}/examples/dmv/results/carRentalsPlusPeriphery.dot');
select *
from class LocalSchema
where name = 'CAR_RENTALS' then (
follow composite forward destination class ColumnSet then (
follow origin end client then (
follow destination end supplier destination class ColumnSet
)
union
follow origin end supplier then (
follow destination end client destination class ColumnSet
)
) gather with parent then (
follow composite backward destination class LocalSchema
)
);
call dmv_test.dmv_render_graphviz(
null,
'${FARRAGO_HOME}/examples/dmv/carRentalsOnly.lurql',
'${FARRAGO_HOME}/examples/dmv/objectDependenciesReversed.xml',
'${FARRAGO_HOME}/examples/dmv/results/carRentalsReversed.dot');
<SetByAssoc
assoc="DependencySupplier"
mapping="REVERSAL"/>
call dmv_test.dmv_render_graphviz(
null,
'${FARRAGO_HOME}/examples/dmv/customersDownstream.lurql',
'${FARRAGO_HOME}/examples/dmv/objectDependencies.xml',
'${FARRAGO_HOME}/examples/dmv/results/customersDownstream.dot');
select *
from class ColumnSet where name='CUSTOMERS' then (
recursively (
follow origin end supplier then (
follow destination end client destination class ColumnSet
)
) then (
follow composite backward destination class LocalSchema
)
);
call dmv_test.dmv_render_graphviz(
null,
'${FARRAGO_HOME}/examples/dmv/eventsUpstream.lurql',
'${FARRAGO_HOME}/examples/dmv/objectDependencies.xml',
'${FARRAGO_HOME}/examples/dmv/results/eventsUpstream.dot');
select *
from class ColumnSet where name='EVENTS' then (
recursively (
follow origin end client then (
follow destination end supplier destination class ColumnSet
)
)
) gather with parent then (
follow composite backward destination class LocalSchema
);
call dmv_test.dmv_render_graphviz(
null,
'${FARRAGO_HOME}/examples/dmv/registrationsUpAndDownStream.lurql',
'${FARRAGO_HOME}/examples/dmv/objectDependencies.xml',
'${FARRAGO_HOME}/examples/dmv/results/registrationsUpAndDownStream.dot');
select *
from class ColumnSet where name='REGISTRATIONS' then (
recursively (
follow origin end supplier then (
follow destination end client destination class ColumnSet
)
)
union
recursively (
follow origin end client then (
follow destination end supplier destination class ColumnSet
)
)
) gather with parent then (
follow composite backward destination class LocalSchema
);