Monday, 24 June 2019

Version 7 is coming (soon)

Starting in autumn 2018 I have been developing StrongDBMS (, Twitter #StrongDBMS) which incorporates many of PyrrhoDB's ideas, but handles concurrency better than other DBMS I have managed to test. The reasons and source code are written up in GitHub, see .These tests also showed up some weaknesses in Pyrrho.
Both Strong and Pyrrho use a minimal set of locks to manage concurrency and ensure ACID properties: one lock is for the DBMS itself, and one for each database file. Unfortunately, in versions up to 6.3, Pyrrho transactions can involve more than one database, and the database is stored in a sequence of files (with file names including sequence numbers 001 etc if required). Both of these "improvements" in Pyrrho make verification of ACID properties more difficult.
I will produce a cleaned up version 7 of Pyrrho that will be backwards compatible with Pyrrho 6.3, apart from lacking multi-database connections and supporting only one file per database. 

Thursday, 13 December 2018

Mandatory Access Control

Pyrrho now provides a free-to-use simulation of Bell-LaPadula security, similar to the US Department of Defense Orange Book. The basic idea is well-explained in Wikipedia and popular database textbooks and there corrent implementations of this security model in Oracle 18.
A feature of the system is that a table can contain rows with different security classifications, and users will be able to see a subset of these detemined by their security clearance. Users can create or modify data that matches their clearance.
The basic idea is that there are security levels D,C,B and A, and security is managed by the database owner (the security administrator SA). The SA can give users  a security clearance, and can give a classification based on these levels to objects such as tables and rows in the database.
By default all access to tables is then subject to security clearance, but the SA can limit enforcement in a table to any combination of read, insert, update and delete. In addition the SA can specify two sets of identifiers (Pyrrho calls these groups and references), so that security clearance and classification can be enhanced using subsets of these identifiers.
To whet your appetite, here is  a simple test script [as revised 5 January 2019]:

A. Logged in as database owner
1. Starting with empty database "mac"
create table A(B int,C char)
create table D(E char primary key) security level D groups Army Navy references Defence scope read
create table F(G char primary key,H char security level C)
revoke "mac" from public
2. Create some users with and without clearance. (On Windows prefix the user names with Domain\)
grant "mac" to "Student"
grant "mac" to "Fred"
grant security level B groups Army references Defence Cyber to "Student"
3. Add some rows with and without classification
insert into A values(2,'Two')
insert into A values(3,'Three') security level C
insert into D values('Test')
insert into F values('MI6','')
4. Check we can see two rows in A, one row in D and two columns in F
table A
table D
table F

B. Logged in as Fred
5. Check we can only see one row in A, one column in F, and nothing in D
table A
table D
table F
6. Check we can add a row in A, D and F
insert into A values(4,'Four')
insert into D values('Fred wrote this')
insert into F values('UWS')

C. Logged in as Student
7. Check we can see three rows in A, two rows in D and two columns in F
table A
table D
table F

8. Check we can' only make changes in table D (enforcement in D is only for read)
update A set c = 'No' where b=2
update A set c = 'No' where b=3
update A set c = 'No' where b=4
update D set E='Fred?' where E<>'Test'
update F set H='' where G='MI6'
update F set H='' where G='UWS'
9. Check we can add and update rows in all three tables
insert into A values(5,'Fiv')
update A set c='Five' where b=5
insert into D values('Another')
insert into F values('BBC','')
update F set H='' where G='BBC'
10. Check we can see our rows and changes
table A
table D
table F

D. Logged in as Fred
11. Check Fred can't see the new rows
table A
table D
table F

E. Logged in as database owner
12. Check all tables including the security information
select B,C,security from A
select E,security from D
select G,H,security from F
select * from A where security=level c
update A set security=level C where security=level B
update F set security=level D where G='BBC'
table "Sys$Classification"

F. Logged in as Student
13. Check we can still see our row in A
select * from a where b=5
14. Check we can no longer update our rows in A or F
delete from A where b=5
update F set H='' where G='BBC'

G. Logged in as Fred
15. Check we can see the row about the BBC

H. Logged in as database owner
16. Check that auditing has been happening
table "Sys$Audit"

Full details of Pyrrho's implementation are in the manual at section 3.4.2 and the syntax pages on have been updated to include the syntax extensions. The SA is able to manage all of this with the help of a set of system tables such as Sys$Classification. A commercial vendor such as Oracle provides many tools to assist in this process.
The implementation in Pyrrho is new and no doubt will evolve over the next weeks. Comments please to . Also follow me @MalcolmCrowe  #PyrrhoDBMS .
(Update 5 Jan 2019: the manual has been updated to remove an incorrect assertion about changes to security clearance. Such changes can have no effect on ongoing transactions.)

Friday, 23 November 2018

Recording access to sensitive data

Today there is considerable interest in access auditing, and a requirement in some jurisdictions for companies to record use of sensitive data.
Pyrrho already indelibly records changes to all data together with the user/role and time of changes, and watches reading of data during transactions to construct simple constraints on a transaction being committed. 
As a matter of fact, few experts agree with this feature, since it means the inclusion of a read operation in a transaction will prevent the transaction being committed a concurrent transaction commits a modification of any of the data that has been read. Pyrrho enforces this approach however, because the user whose transaction is prevented from committing is the same one who (presumably deliberately) included the read operation in the transaction.
The present discussion also considers read operations but in a different way. Here we want to distinguish sensitive data (say at the data type level) and immediately record access to it (by anyone other than the database owner), whether or not the current operation is ever committed.
These features [updated: 27 November] are available in Pyrrho version 6.3. The audit record is merged into the transaction log and a system table gives access to all the details.
From the manual:
Sec 1.5: 
Version 6.3 adds support for “sensitive” data, for which any access is auditable. Columns, domains and types can be declared SENSITIVE[1]. Sensitive values are not assignment-compatible with anything that is not sensitive, and there is a sensitive property inherited by any object that contains a sensitive data type. This means for example that the sum of sensitive data is still sensitive. The transaction log will contain a record of every access to sensitive values (apart from by the database owner), even if the transaction is rolled back. These details are visible in the Sys$Audit system table (see section 8.3.1).
Sec 7.4:
Type  (StandardType | DefinedType | Domain_id | Type_id | REF’(‘TableReference’)’) [UriType] [SENSITIVE] .
Sec 8.3.1:

8.3.1 Sys$Audit

The location of this access record in the transaction log
The defining position of the accessing user
The defining position of the sensitive table or view object
The time of the access in ticks
Audit records are only for committed sensitive data. Entries come from physical Audit records, and are added immediately on access (do not wait for transaction commit).

8.3.2 Sys$AuditKey

The location of the access record in the transaction log
The ordinal position of the key (0 based)
The defining position of the key column
A string representation of the key value at this position
Key information for audit records comes from the filters used to access a sensitive object. For example, if a record is inserted in a table, there is no applicable filter, the audit record will apply to the whole table, and there will be no key information here.
Comments by email are welcome.

[1] SENSITIVE is a reserved word in SQL that normally applies to cursor sensitivity. The usage in Pyrrho described here is quite different, and the keyword comes at the end of a type clause (see section 7.4).

Wednesday, 21 November 2018

Rethinking Shareable Data Structures

I have been recently developing a set of data structures following on from Okasaki's Purely Functional Data Structures. There is a lot to be gained by using immutable data structures, that is, where all the fields are public readonly in C# or public final in Java. Strings in C# and Java already have this property and it turns out to be remarkably easy to develop all the usual data structure types with this property. Something of the kind had already started to happen in Pyrrho: many of Pyrrho's data structures are immutable, and Pyrrho uses Bookmarks instead of Iterators. Specifically, the benefits (as with strings) are
  •  a snapshot is obtained by a simple assignment, so rollback is a breeze
  •  structures can be modified while a traversal continues with the previous state#
  •  they are thread-safe and safe to pass as a parameter in C# or Java, so that
  •  these data structures never need to be locked
The price to be paid is extra work for the garbage collector: this is a reasonable trade-off.
So the time seemed ripe for a serious approach to #ShareableDataStructures and the fruits of these labours are emerging at . Eventually the classes will be rich enough to implement a DBMS, and the plan is to implement everything in C# and Java, and then Python later. Efforts in the DBMS direction are currently called #StrongDBMS . A lot will depend on the performance of the TPCC benchmark.
It is natural to ask what this might mean for Pyrrho. It does seem like a natural evolution (Pyrrho 7.0 maybe), but some of the Pyrrho code would be a real nuisance to transform. Time will tell.

Tuesday, 2 October 2018

Window Functions

A basic set of window functions are supported in PyrrhoDBMS. The full set of OLAP functions as defined in ISO 9075 used to be supported and can be again if there is demand: email me if you think this would be useful or if you find any issues (my direct email at UWS is in the download).

Saturday, 11 August 2018

Latest version of Pyrrho 6.2

This version fixes a number of long-standing bugs in Pyrrho, including the following significant areas:
  • Exit handlers
  • Check constraints
  • Triggers
  • OSPStudio
  • Row count
The Java Connector (PyrrhoJC) is also being fixed for Java SE, and more changes are expected.
In addition, some syntax error messages have been made more helpful. Many thanks for those who have submitted performance reports - I have tried your patience by taking so long to fix them.
Please send me details of any problems you find (

Thursday, 19 July 2018

RESTViews: the "Sierra Leone" example

A previous post on this blog (More details about RESTViews) showed the range of HTTP queries that could be automatically generated by Pyrrho from a simple View definition. This post takes extends the examples, using a set of sample MySQL databases constructed for the purpose by Fritz Laux.
A number of steps are required to set up the MYSQL databases and allow remote SELECT connections to the view, so these will not detailed here. The important point is that once the remote views have been defined to a Pyrrho database, a large set of SQL queries (with filters, aggregations and joins to other local tables) are supported using automatic creation of the appropriate SQL requests to the remote MySQL databases. The local Pyrrho database is not modified during any of these tests as none of the views are materialised and no schema changes are made. The data requested (volume of data transferred from the remote databases) is minimised as shown in these blog posts. Full technical details of the mechanism are given in the Pyrrho distribution at, which contains a document "The Sierra Leone example" giving more details than are given here.
In this example, the remote view is defined in Pyrrho as follows (the syntax uses an SQL extension that Pyrrho calls RESTView):
 [create view patientdataSL of ("hospID" char,"hospDesc" char,"patientID" int,"rCode" int,"address" char, "birthdate" date,"admission" date,"ICD10" char,"diagnosis" char,"treatments" char) as get using hospitalssl]
where hospitalssl is the following small table:
'CMH''Choithram Memorial Hospital''http://root:admin@localhost:8078/sleone/patientrecordcmh'
'HS''Holy Spirit Hospital''http://root:admin@localhost:8078/sleone/patientrecordholyspirit'
'MABESSS''St John of God Catholic (Mabesseneh) Hospital''http://root:admin@localhost:8078/sleone/patientrecordmabesss'
The first column is a key to identify the remote contributor database, at the url shown.
The remote contributor databases supply views for the given credentials containing the remaining columns in the above view definition. All three databases are in a MySQL database on localhost, and of course in a real example they would be on different hosts. The HTTP listener on port 8078 is the HTTP interface restif available at GitHub - this interface needs to run on the same server as the MySQL database but has no privileges or configuration of its own. It simply accepts one or more SQL statements from and returns SQL data in Json format.
With this setup, no further programming is required to access data from the remote views, as Pyrrho generates any MySQL queries that may be required. Further local views can be defined as indicated below and the code below includesjoins aith a local table called deomgraphicSL.
Consider the following SQL statements and the corresponding SQL queries sent to the remote contributors (Pyrrho request is in black, MySQL generated query for one remote hospital in blue):

[select * from patientdataSL where "patientID" = 10015]
select 'CMH' as hospID,'Choithram Memorial Hospital' as hospDesc,patientID,rCode,address,birthdate,admission,ICD10,diagnosis,treatments from patientrecordcmh where patientID=10015

select count("patientID") from patientdataSL
select COUNT(patientID) as C_298 from patientrecordcmh
This request of course returns a single row from each hospital with its number of patients and Pyrrho gives the total of these counts as 30003.

select count(*) from patientdatasl where icd10='N73.4'
select COUNT(*) as C_323 from patientrecordcmh where ICD10='N73.4'
This time the count is 3.

select "patientID" from patientdataSL where icd10='N73.4'
select patientID from patientrecordcmh where ICD10='N73.4'
Three patientIDs are returned 0 from the first hospital, 2 from the second, and 1 from the third.

[select count( *) as "numPatients", "rCode", count( *)*1.0 / "totalinhabitants" as "percentageOfPopulation" from patientdataSL natural join demographicSL where "rCode" < 1010 group by "rCode","totalinhabitants" order by "percentageOfPopulation" desc]
select COUNT(*) as C_275,rCode from patientrecordcmh group by rCode having rCode < 1010
This fetches 9 rows from each hospital, and results in a table of 9 rows sorted by proportionOfPopulation.

[create view patientSummary as select "rCode", extract(year from "admission")-extract(year from "birthdate") as "age", extract(year from "admission") as "adyear", icd10, count(*) as patients from patientDataSL group by "rCode", "age", "adyear", icd10]
select * from patientsummary where icd10='N73.4'
select rCode as rCode,(YEAR(admission)-YEAR(birthdate)) as age,(YEAR(admission) as adyear,ICD10 as ICD10,COUNT(*) as C_856 from patientrecordcmh group by rCode,age,adyear,ICD10 having ICD10='N73.4'
This gives the rCode, age and admission year for the three patients mentioned above.

create view patientAnalysis as select * from patientSummary natural join demographicSL
select * from patientanalysis where icd10='N73.4'
select rCode as rCode,(YEAR(admission)-YEAR(birthdate)) as age,(YEAR(admission) as adyear,ICD10 as ICD10,COUNT(*) as C_903 from patientrecordcmh group by rCode,age,adyear,ICD10 having ICD10='N73.4'

[select "rCode", icd10, "age", patients*100.0/"under10" as percentage from patientAnalysis where ICD10='N17.1' and "age"<10]
select rCode as rCode,(YEAR(admission)-YEAR(birthdate)) as age,(YEAR(admission) as adyear,ICD10 as ICD10,COUNT(*) as C_972 from patientrecordcmh group by rCode,age,adyear,ICD10 having ICD10='N73.4'
These adds to the previous details some demographic information about the regions involved. The generated SQL is similar (Pyrrho currently does not pass on the condition on the calculated field age).

[select coalesce(young.icd10,older.icd10) as "icd10", youngPat, oldPat from (select icd10, sum(patients) as youngPat from patientsummary where "age"<10 and="" icd10="">'Z87' group by icd10) young full join (select icd10, sum(patients) as oldPat from patientsummary where "age">50 and icd10>'Z87' group by icd10) older on young.icd10=older.icd10 order by youngPat desc]
select rCode as rCode,(YEAR(admission)-YEAR(birthdate)) as age,YEAR(admission) as adyear,ICD10 as ICD10,COUNT(*) as C_253 from patientrecordcmh group by rCode,age,adyear,ICD10 having ICD10>'Z87'
Each half of this join retrieves 100, 97, and 70 records from the three hospitals, and groups the results into a table with 56 rows. Also the descending order is honoured. The conversions and processing are very fast.