Lots of DB-related updates:

Moved schema file out of chrome and removed XML tags, since it will no longer be accessed by XMLHTTP

Changed schema updater to use XPCOM components rather than XMLHTTP

Converted DB class to a singleton named Scholar_DB

Scholar_DB.query() now returns associative array similar to mysql_fetch_assoc() for SELECT statements rather than a mozIStorageStatementWrapper -- the mozStorage executeDataSet() function doesn't work yet, so we do it this way

Added DB functions:

   - beginTransaction(), commitTransaction(), rollbackTransaction()
   - columnQuery() -- one column, multiple rows, returned as array indexed by row
   - getColumns() and getColumnHash

DB query functions can now handle bind parameters passed as an array of object literals: e.g. [{'int':2},{'string':'foobar'}]

valueQuery() now returns an int for COUNT(*) queries, so the result can be tested without a "0" being true

Changed _initializeSchema to drop existing tables before creating new ones, hacked with try/catch until DROP TABLE IF EXISTS works with the mozStorage extension (it's already in the latest SQLite release)

Added DB_REBUILD config flag to manually trigger schema regeneration

Added debug logging at level 5 for all SQL queries

Updated sample data
This commit is contained in:
Dan Stillman 2006-03-14 11:34:17 +00:00
parent 2a866fe3cd
commit 50eddb05ee
2 changed files with 308 additions and 118 deletions

View file

@ -1,9 +1,7 @@
var scholarDB = new Scholar_DB();
/*
* DB connection and schema management class
*/
function Scholar_DB(){
var Scholar_DB = new function(){
// Private members
var _connection;
@ -11,9 +9,14 @@ function Scholar_DB(){
this.query = query;
this.valueQuery = valueQuery;
this.rowQuery = rowQuery;
this.columnQuery = columnQuery;
this.statementQuery = statementQuery;
this.getColumns = getColumns;
this.getColumnHash = getColumnHash;
this.updateSchema = updateSchema;
this.beginTransaction = beginTransaction;
this.commitTransaction = commitTransaction;
this.rollbackTransaction = rollbackTransaction;
/////////////////////////////////////////////////////////////////
//
@ -24,33 +27,56 @@ function Scholar_DB(){
/*
* Run an SQL query
*
* Optional _params_ is an array of bind parameters in the form
* [{'int':2},{'string':'foobar'}]
*
* Returns:
* - mozIStorageStatementWrapper for SELECT's
* - Associative array (similar to mysql_fetch_assoc) for SELECT's
* - lastInsertId for INSERT's
* - TRUE for other successful queries
* - FALSE on error
*/
function query(sql){
function query(sql,params){
var db = _getDBConnection();
try {
// Parse out the SQL command being used
var op = sql.match(/^[^a-z]*[^ ]+/i).toString().toLowerCase();
var op = sql.match(/^[^a-z]*[^ ]+/i);
if (op){
op = op.toString().toLowerCase();
}
// If SELECT statement, return result
if (op=='select'){
var wrapper =
Components.classes['@mozilla.org/storage/statement-wrapper;1']
.createInstance(Components.interfaces.mozIStorageStatementWrapper);
// Until the native dataset methods work (or at least exist),
// we build a multi-dimensional associative array manually
wrapper.initialize(db.createStatement(sql));
return wrapper;
var statement = statementQuery(sql,params);
var dataset = new Array();
while (statement.executeStep()){
var row = new Array();
for(var i=0; i<statement.columnCount; i++) {
row[statement.getColumnName(i)] = statement.getAsUTF8String(i);
}
dataset.push(row);
}
statement.reset();
return dataset.length ? dataset : false;
}
else {
db.executeSimpleSQL(sql);
if (params){
var statement = statementQuery(sql,params);
statement.execute();
}
else {
Scholar.debug(sql,5);
db.executeSimpleSQL(sql);
}
if (op=='insert'){
return db.lastInsertId;
return db.lastInsertRowID;
}
// DEBUG: Can't get affected rows for UPDATE or DELETE?
else {
@ -58,9 +84,8 @@ function Scholar_DB(){
}
}
}
catch(ex){
alert(db.lastErrorString);
return false;
catch (e){
throw(e + ' (SQL error: ' + db.lastErrorString + ')');
}
}
@ -68,21 +93,26 @@ function Scholar_DB(){
/*
* Query a single value and return it
*/
function valueQuery(sql){
function valueQuery(sql,params){
var db = _getDBConnection();
try {
var statement = db.createStatement(sql);
var statement = statementQuery(sql,params);
}
catch (e){
alert(db.lastErrorString);
return false;
throw(db.lastErrorString);
}
// No rows
if (!statement.executeStep()){
statement.reset();
return false;
}
var value = statement.getAsUTF8String(0);
if (sql.indexOf('SELECT COUNT(*)') > -1){
var value = statement.getAsInt32(0);
}
else {
var value = statement.getAsUTF8String(0);
}
statement.reset();
return value;
}
@ -91,29 +121,119 @@ function Scholar_DB(){
/*
* Run a query and return the first row
*/
function rowQuery(sql){
var result = query(sql);
if (result && result.step()){
return result.row;
function rowQuery(sql,params){
var result = query(sql,params);
if (result){
return result[0];
}
}
/*
* Run a query, returning a mozIStorageStatement for direct manipulation
* Run a query and return the first column as a numerically-indexed array
*/
function statementQuery(sql){
function columnQuery(sql,params){
var statement = statementQuery(sql,params);
if (statement){
var column = new Array();
while (statement.executeStep()){
column.push(statement.getAsUTF8String(0));
}
statement.reset();
return column.length ? column : false;
}
return false;
}
/*
* Run a query, returning a mozIStorageStatement for direct manipulation
*
* Optional _params_ is an array of bind parameters in the form
* [{'int':2},{'string':'foobar'}]
*/
function statementQuery(sql,params){
var db = _getDBConnection();
try {
return db.createStatement(sql);
Scholar.debug(sql,5);
var statement = db.createStatement(sql);
}
catch (e){
throw(db.lastErrorString);
}
if (statement && params){
for (var i=0; i<params.length; i++){
if (typeof params[i]['int'] != 'undefined'){
Scholar.debug('Binding parameter ' + (i+1) + ': ' +
params[i]['int'],5);
statement.bindInt32Parameter(i,params[i]['int']);
}
else if (typeof params[i]['string'] != 'undefined'){
Scholar.debug('Binding parameter ' + (i+1) + ': "' +
params[i]['string'] + '"',5);
statement.bindUTF8StringParameter(i,params[i]['string']);
}
}
}
return statement;
}
function beginTransaction(){
var db = _getDBConnection();
Scholar.debug('Beginning DB transaction',5);
db.beginTransaction();
}
function commitTransaction(){
var db = _getDBConnection();
Scholar.debug('Committing transaction',5);
db.commitTransaction();
}
function rollbackTransaction(){
var db = _getDBConnection();
Scholar.debug('Rolling back transaction',5);
db.rollbackTransaction();
}
function getColumns(table){
var db = _getDBConnection();
try {
var sql = "SELECT * FROM " + table + " LIMIT 1";
var statement = statementQuery(sql);
var cols = new Array();
for (var i=0,len=statement.columnCount; i<len; i++){
cols.push(statement.getColumnName(i));
}
return cols;
}
catch (e){
Scholar.debug(e,1);
return false;
}
}
function getColumnHash(table){
var cols = getColumns(table);
var hash = new Array();
if (cols.length){
for (var i=0; i<cols.length; i++){
hash[cols[i]] = true;
}
}
return hash;
}
/*
* Checks if the DB schema exists and is up-to-date, updating if necessary
*/
@ -125,12 +245,17 @@ function Scholar_DB(){
}
else if (DBVersion < SCHOLAR_CONFIG['DB_VERSION']){
if (!DBVersion){
dump('Database does not exist -- creating\n');
Scholar.debug('Database does not exist -- creating\n');
return _initializeSchema();
}
return _migrateSchema(DBVersion);
}
else if (SCHOLAR_CONFIG['DB_REBUILD']){
if (confirm('Erase all data and recreate database from schema?')){
return _initializeSchema();
}
}
}
@ -180,22 +305,42 @@ function Scholar_DB(){
/*
* Load in SQL schema
*
* Returns an _array_ of SQL statements for feeding into query()
*/
function _getSchemaSQL(){
// We pull the schema from an external file so we only have to process
// it when necessary
var req = new XMLHttpRequest();
req.open("GET", "chrome://scholar/content/schema.xml", false);
req.send(null);
var file = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager)
.getInstallLocation(SCHOLAR_CONFIG['GUID'])
.getItemLocation(SCHOLAR_CONFIG['GUID']);
file.append('schema.sql');
var schemaVersion =
req.responseXML.documentElement.getAttribute('version');
// Open an input stream from file
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
istream.init(file, 0x01, 0444, 0);
istream.QueryInterface(Components.interfaces.nsILineInputStream);
var line = {}, sql = '', hasmore;
// Fetch the schema version from the first line of the file
istream.readLine(line);
var schemaVersion = line.value.match(/-- ([0-9]+)/)[1];
do {
hasmore = istream.readLine(line);
sql += line.value + "\n";
} while(hasmore);
istream.close();
if (schemaVersion!=SCHOLAR_CONFIG['DB_VERSION']){
throw("Scholar config version does not match schema version");
}
return req.responseXML.documentElement.firstChild.data;
return sql;
}
@ -203,10 +348,26 @@ function Scholar_DB(){
* Retrieve the version attribute of the schema SQL XML
*/
function _getSchemaSQLVersion(){
var req = new XMLHttpRequest();
req.open("GET", "chrome://scholar/content/schema.xml", false);
req.send(null);
return req.responseXML.documentElement.getAttribute('version');
var file = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager)
.getInstallLocation(SCHOLAR_CONFIG['GUID'])
.getItemLocation(SCHOLAR_CONFIG['GUID']);
file.append('schema.sql');
// Open an input stream from file
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
istream.init(file, 0x01, 0444, 0);
istream.QueryInterface(Components.interfaces.nsILineInputStream);
var line = {};
// Fetch the schema version from the first line of the file
istream.readLine(line);
var schemaVersion = line.value.match(/-- ([0-9]+)/)[1];
istream.close();
return schemaVersion;
}
@ -214,8 +375,32 @@ function Scholar_DB(){
* Create new DB schema
*/
function _initializeSchema(){
query(_getSchemaSQL());
query("INSERT INTO version VALUES (" + SCHOLAR_CONFIG['DB_VERSION'] + ")");
// Until DROP TABLE IF EXISTS works with the mozStorage extension
try { query('DROP TABLE version'); } catch(e){}
try { query('DROP TABLE objects'); } catch(e){}
try { query('DROP TABLE objectTypes'); } catch(e){}
try { query('DROP TABLE fieldFormats'); } catch(e){}
try { query('DROP TABLE fields'); } catch(e){}
try { query('DROP TABLE objectTypeFields'); } catch(e){}
try { query('DROP TABLE objectData'); } catch(e){}
try { query('DROP TABLE keywords'); } catch(e){}
try { query('DROP TABLE objectKeywords'); } catch(e){}
try { query('DROP TABLE creators'); } catch(e){}
try { query('DROP TABLE creatorTypes'); } catch(e){}
try { query('DROP TABLE objectCreators'); } catch(e){}
try { query('DROP TABLE folders'); } catch(e){}
try {
beginTransaction();
var sql = _getSchemaSQL();
query(sql);
query("INSERT INTO version VALUES (" + SCHOLAR_CONFIG['DB_VERSION'] + ")");
commitTransaction();
}
catch(e){
alert(e);
rollbackTransaction();
}
}
@ -230,17 +415,22 @@ function Scholar_DB(){
throw("Scholar config version does not match schema version");
}
dump('Updating DB from version ' + fromVersion + ' to ' + toVersion + '\n');
Scholar.debug('Updating DB from version ' + fromVersion + ' to ' + toVersion + '\n');
// Step through version changes until we reach the current version
//
// Each block performs the changes necessary to move from the
// previous revision to that one.
// previous revision to that one.
//
// N.B. Be sure to call _updateDBVersion(i) at the end of each block!
for (var i=fromVersion+1; i<=toVersion; i++){
for (var i=parseInt(fromVersion) + 1; i<=toVersion; i++){
if (i==1){
// For now, just wipe and recreate
if (i==2){
_initializeSchema();
}
if (i==3){
// do stuff
// _updateDBVersion(i);
}

View file

@ -1,4 +1,5 @@
<schema version="2">
-- 2
-- IF EXISTS not yet available in available mozStorage binaries,
-- so we fake it with a bunch of try/catches in the _initializeSchema()
@ -11,17 +12,16 @@
CREATE TABLE objects (
objectID INTEGER PRIMARY KEY,
objectTypeID INT,
objectTitle TEXT,
objectDate DATETIME,
objectDateAdded DATETIME DEFAULT CURRENT_TIMESTAMP,
objectDateModified DATETIME DEFAULT CURRENT_TIMESTAMP,
objectSource TEXT,
objectRights TEXT,
title TEXT,
dateAdded DATETIME DEFAULT CURRENT_TIMESTAMP,
dateModified DATETIME DEFAULT CURRENT_TIMESTAMP,
source TEXT,
rights TEXT,
folderID INT,
orderIndex INT,
FOREIGN KEY (folderID) REFERENCES folders(folderID)
);
CREATE INDEX folderID ON objects (folderID);
CREATE INDEX folderID ON objects(folderID);
-- DROP TABLE IF EXISTS objectTypes;
CREATE TABLE objectTypes (
@ -82,10 +82,11 @@
-- DROP TABLE IF EXISTS creators;
CREATE TABLE creators (
creatorID INTEGER PRIMARY KEY,
creatorTypeID INT,
creatorID INT,
creatorTypeID INT DEFAULT 1,
firstName TEXT,
lastName TEXT,
PRIMARY KEY (creatorID),
FOREIGN KEY (creatorTypeID) REFERENCES creatorTypes(creatorTypeID)
);
@ -99,7 +100,7 @@
CREATE TABLE objectCreators (
objectID INT,
creatorID INT,
orderIndex INT DEFAULT 1,
orderIndex INT DEFAULT 0,
PRIMARY KEY (objectID, creatorID),
FOREIGN KEY (objectID) REFERENCES objects(objectID),
FOREIGN KEY (creatorID) REFERENCES creators(creatorID)
@ -113,8 +114,8 @@
orderIndex INT,
FOREIGN KEY (parentFolderID) REFERENCES folders(folderID)
);
CREATE INDEX parentFolderID ON folders(parentFolderID);
INSERT INTO folders VALUES (0, 'root', 0, 0);
-- Some sample data
INSERT INTO objectTypes VALUES (1,'Book');
@ -124,16 +125,16 @@
INSERT INTO "fieldFormats" VALUES(2, '[0-9]*', 1);
INSERT INTO "fieldFormats" VALUES(3, '[0-9]{4}', 1);
INSERT INTO fields VALUES (1,'Series',NULL);
INSERT INTO fields VALUES (2,'Volume',NULL);
INSERT INTO fields VALUES (3,'Number',NULL);
INSERT INTO fields VALUES (4,'Edition',NULL);
INSERT INTO fields VALUES (5,'Place',NULL);
INSERT INTO fields VALUES (6,'Publisher',NULL);
INSERT INTO fields VALUES (7,'Year',NULL);
INSERT INTO fields VALUES (8,'Pages',NULL);
INSERT INTO fields VALUES (1,'series',NULL);
INSERT INTO fields VALUES (2,'volume',NULL);
INSERT INTO fields VALUES (3,'number',NULL);
INSERT INTO fields VALUES (4,'edition',NULL);
INSERT INTO fields VALUES (5,'place',NULL);
INSERT INTO fields VALUES (6,'publisher',NULL);
INSERT INTO fields VALUES (7,'year',3);
INSERT INTO fields VALUES (8,'pages',2);
INSERT INTO fields VALUES (9,'ISBN',NULL);
INSERT INTO fields VALUES (10,'Publication',NULL);
INSERT INTO fields VALUES (10,'publication',NULL);
INSERT INTO fields VALUES (11,'ISSN',NULL);
INSERT INTO objectTypeFields VALUES (1,1,1);
@ -150,62 +151,61 @@
INSERT INTO objectTypeFields VALUES (2,3,3);
INSERT INTO objectTypeFields VALUES (2,8,4);
INSERT INTO "objects" VALUES(1, 1, 'Online connections: Internet interpersonal relationships', NULL, '2006-03-12 05:24:40', '2006-03-12 05:24:40', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(2, 1, 'Computer-Mediated Communication: Human-to-Human Communication Across the Internet', NULL, '2006-03-12 05:25:50', '2006-03-12 05:25:50', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(3, 2, 'Residential propinquity as a factor in marriage selection', NULL, '2006-03-12 05:26:37', '2006-03-12 05:26:37', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(4, 1, 'Connecting: how we form social bonds and communities in the Internet age', NULL, '2006-03-12 05:27:15', '2006-03-12 05:27:15', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(5, 1, 'Male, Female, Email: The Struggle for Relatedness in a Paranoid Society', NULL, '2006-03-12 05:27:36', '2006-03-12 05:27:36', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(6, 2, 'Social Implications of Sociology', NULL, '2006-03-12 05:27:53', '2006-03-12 05:27:53', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(7, 1, 'Social Pressures in Informal Groups: A Study of Human Factors in Housing', NULL, '2006-03-12 05:28:05', '2006-03-12 05:28:05', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(8, 1, 'Cybersociety 2.0: Revisiting Computer-Mediated Community and Technology', NULL, '2006-03-12 05:28:37', '2006-03-12 05:28:37', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(9, 2, 'The Computer as a Communication Device', NULL, '2006-03-12 05:29:03', '2006-03-12 05:29:03', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(10, 2, 'What Does Research Say about the Nature of Computer-mediated Communication: Task-Oriented, Social-Emotion-Oriented, or Both?', NULL, '2006-03-12 05:29:12', '2006-03-12 05:29:12', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(11, 1, 'The second self: computers and the human spirit', NULL, '2006-03-12 05:30:38', '2006-03-12 05:30:38', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(12, 1, 'Life on the screen: identity in the age of the Internet', NULL, '2006-03-12 05:30:49', '2006-03-12 05:30:49', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(13, 2, 'The computer conference: An altered state of communication', NULL, '2006-03-12 05:31:00', '2006-03-12 05:31:00', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(14, 2, 'Computer Networks as Social Networks: Collaborative Work, Telework, and Community', NULL, '2006-03-12 05:31:17', '2006-03-12 05:31:17', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(15, 1, 'The Internet in everyday life', NULL, '2006-03-12 05:31:41', '2006-03-12 05:31:41', NULL, NULL, NULL, NULL);
INSERT INTO "objects" VALUES(1, 1, 'Online connections: Internet interpersonal relationships', '2006-03-12 05:24:40', '2006-03-12 05:24:40', NULL, NULL, 0, 5);
INSERT INTO "objects" VALUES(2, 1, 'Computer-Mediated Communication: Human-to-Human Communication Across the Internet', '2006-03-12 05:25:50', '2006-03-12 05:25:50', NULL, NULL, 0, 2);
INSERT INTO "objects" VALUES(3, 2, 'Residential propinquity as a factor in marriage selection', '2006-03-12 05:26:37', '2006-03-12 05:26:37', NULL, NULL, 0, 1);
INSERT INTO "objects" VALUES(4, 1, 'Connecting: how we form social bonds and communities in the Internet age', '2006-03-12 05:27:15', '2006-03-12 05:27:15', NULL, NULL, 0, 4);
INSERT INTO "objects" VALUES(5, 1, 'Male, Female, Email: The Struggle for Relatedness in a Paranoid Society', '2006-03-12 05:27:36', '2006-03-12 05:27:36', NULL, NULL, 0, 3);
INSERT INTO "objects" VALUES(6, 2, 'Social Implications of Sociology', '2006-03-12 05:27:53', '2006-03-12 05:27:53', NULL, NULL, 0, 7);
INSERT INTO "objects" VALUES(7, 1, 'Social Pressures in Informal Groups: A Study of Human Factors in Housing', '2006-03-12 05:28:05', '2006-03-12 05:28:05', NULL, NULL, 0, 6);
INSERT INTO "objects" VALUES(8, 1, 'Cybersociety 2.0: Revisiting Computer-Mediated Community and Technology', '2006-03-12 05:28:37', '2006-03-12 05:28:37', NULL, NULL, 0, 9);
INSERT INTO "objects" VALUES(9, 2, 'The Computer as a Communication Device', '2006-03-12 05:29:03', '2006-03-12 05:29:03', NULL, NULL, 0, 8);
INSERT INTO "objects" VALUES(10, 2, 'What Does Research Say about the Nature of Computer-mediated Communication: Task-Oriented, Social-Emotion-Oriented, or Both?', '2006-03-12 05:29:12', '2006-03-12 05:29:12', NULL, NULL, 0, 13);
INSERT INTO "objects" VALUES(11, 1, 'The second self: computers and the human spirit', '2006-03-12 05:30:38', '2006-03-12 05:30:38', NULL, NULL, 0, 10);
INSERT INTO "objects" VALUES(12, 1, 'Life on the screen: identity in the age of the Internet', '2006-03-12 05:30:49', '2006-03-12 05:30:49', NULL, NULL, 0, 11);
INSERT INTO "objects" VALUES(13, 2, 'The computer conference: An altered state of communication', '2006-03-12 05:31:00', '2006-03-12 05:31:00', NULL, NULL, 0, 12);
INSERT INTO "objects" VALUES(14, 2, 'Computer Networks as Social Networks: Collaborative Work, Telework, and Community', '2006-03-12 05:31:17', '2006-03-12 05:31:17', NULL, NULL, 0, 14);
INSERT INTO "objects" VALUES(15, 1, 'The Internet in everyday life', '2006-03-12 05:31:41', '2006-03-12 05:31:41', NULL, NULL, 0, 15);
INSERT INTO "objectData" VALUES(1, 7, 2001);
INSERT INTO "objectData" VALUES(1, 5, 'Cresskill, N.J.');
INSERT INTO "objectData" VALUES(1, 6, 'Hampton Press');
INSERT INTO "objectData" VALUES(2, 7, 2002);
INSERT INTO "objectData" VALUES(2, 6, 'Allyn &amp; Bacon Publishers');
INSERT INTO "objectData" VALUES(2, 6, 'Allyn & Bacon Publishers');
INSERT INTO "objectData" VALUES(2, 8, 347);
INSERT INTO "objectData" VALUES(2, 9, '0-205-32145-3');
INSERT INTO "creators" VALUES(1, NULL, 'Susan B.', 'Barnes');
INSERT INTO "creators" VALUES(2, NULL, 'J.S.', 'Bassard');
INSERT INTO "creators" VALUES(3, NULL, 'Mary', 'Chayko');
INSERT INTO "creators" VALUES(4, NULL, 'Michael', 'Civin');
INSERT INTO "creators" VALUES(5, NULL, 'Paul', 'DiMaggio');
INSERT INTO "creators" VALUES(6, NULL, 'Leon', 'Festinger');
INSERT INTO "creators" VALUES(7, NULL, 'Stanley', 'Schachter');
INSERT INTO "creators" VALUES(8, NULL, 'Kurt', 'Back');
INSERT INTO "creators" VALUES(9, NULL, 'Steven G.', 'Jones');
INSERT INTO "creators" VALUES(10, NULL, 'J.C.R.', 'Licklider');
INSERT INTO "creators" VALUES(11, NULL, 'Robert W.', 'Taylor');
INSERT INTO "creators" VALUES(12, NULL, 'Yuliang', 'Lui');
INSERT INTO "creators" VALUES(13, NULL, 'Sherry', 'Turkle');
INSERT INTO "creators" VALUES(14, NULL, 'J.', 'Vallee');
INSERT INTO "creators" VALUES(15, NULL, 'Barry', 'Wellman');
INSERT INTO "creators" VALUES(1, 1, 'Susan B.', 'Barnes');
INSERT INTO "creators" VALUES(2, 1, 'J.S.', 'Bassard');
INSERT INTO "creators" VALUES(3, 1, 'Mary', 'Chayko');
INSERT INTO "creators" VALUES(4, 1, 'Michael', 'Civin');
INSERT INTO "creators" VALUES(5, 1, 'Paul', 'DiMaggio');
INSERT INTO "creators" VALUES(6, 1, 'Leon', 'Festinger');
INSERT INTO "creators" VALUES(7, 1, 'Stanley', 'Schachter');
INSERT INTO "creators" VALUES(8, 1, 'Kurt', 'Back');
INSERT INTO "creators" VALUES(9, 1, 'Steven G.', 'Jones');
INSERT INTO "creators" VALUES(10, 1, 'J.C.R.', 'Licklider');
INSERT INTO "creators" VALUES(11, 1, 'Robert W.', 'Taylor');
INSERT INTO "creators" VALUES(12, 1, 'Yuliang', 'Lui');
INSERT INTO "creators" VALUES(13, 1, 'Sherry', 'Turkle');
INSERT INTO "creators" VALUES(14, 1, 'J.', 'Vallee');
INSERT INTO "creators" VALUES(15, 1, 'Barry', 'Wellman');
INSERT INTO "objectCreators" VALUES(1, 1, 1);
INSERT INTO "objectCreators" VALUES(2, 1, 1);
INSERT INTO "objectCreators" VALUES(3, 2, 1);
INSERT INTO "objectCreators" VALUES(4, 3, 1);
INSERT INTO "objectCreators" VALUES(5, 4, 1);
INSERT INTO "objectCreators" VALUES(6, 5, 1);
INSERT INTO "objectCreators" VALUES(7, 6, 1);
INSERT INTO "objectCreators" VALUES(8, 9, 1);
INSERT INTO "objectCreators" VALUES(9, 10, 1);
INSERT INTO "objectCreators" VALUES(10, 12, 1);
INSERT INTO "objectCreators" VALUES(11, 13, 1);
INSERT INTO "objectCreators" VALUES(12, 13, 1);
INSERT INTO "objectCreators" VALUES(13, 14, 1);
INSERT INTO "objectCreators" VALUES(14, 15, 1);
INSERT INTO "objectCreators" VALUES(15, 15, 1);
INSERT INTO "objectCreators" VALUES(7, 7, 2);
INSERT INTO "objectCreators" VALUES(7, 8, 3);
INSERT INTO "objectCreators" VALUES(9, 11, 2);
</schema>
INSERT INTO "objectCreators" VALUES(1, 1, 0);
INSERT INTO "objectCreators" VALUES(2, 1, 0);
INSERT INTO "objectCreators" VALUES(3, 2, 0);
INSERT INTO "objectCreators" VALUES(4, 3, 0);
INSERT INTO "objectCreators" VALUES(5, 4, 0);
INSERT INTO "objectCreators" VALUES(6, 5, 0);
INSERT INTO "objectCreators" VALUES(7, 6, 0);
INSERT INTO "objectCreators" VALUES(8, 9, 0);
INSERT INTO "objectCreators" VALUES(9, 10, 0);
INSERT INTO "objectCreators" VALUES(10, 12, 0);
INSERT INTO "objectCreators" VALUES(11, 13, 0);
INSERT INTO "objectCreators" VALUES(12, 13, 0);
INSERT INTO "objectCreators" VALUES(13, 14, 0);
INSERT INTO "objectCreators" VALUES(14, 15, 0);
INSERT INTO "objectCreators" VALUES(15, 15, 0);
INSERT INTO "objectCreators" VALUES(7, 7, 1);
INSERT INTO "objectCreators" VALUES(7, 8, 2);
INSERT INTO "objectCreators" VALUES(9, 11, 1);