2 // Test the Schemamatic functions that live in the Versaplex daemon.
8 using System
.Collections
.Generic
;
9 using System
.Security
.Cryptography
;
16 class SchemamaticTests
: SchemamaticTester
21 public SchemamaticTests()
23 dbus
= new VxDbusSchema(bus
);
24 log
= new WvLog("Schemamatic Tests");
27 // Utility function to put a single schema element.
28 // This may someday be useful to have in the VxDbusSchema class (or even
29 // in ISchemaBackend), but this implementation is a tiny bit too hacky for
30 // general consumption.
31 VxSchemaError
VxPutSchema(string type
, string name
, string text
,
34 VxSchemaElement elem
= new VxSchemaElement(type
, name
, text
, false);
35 VxSchema schema
= new VxSchema(elem
);
36 VxSchemaErrors errs
= VxPutSchema(schema
, opts
);
37 if (errs
== null || errs
.Count
== 0)
40 WVPASSEQ(errs
.Count
, 1);
42 // Just return the first error
43 foreach (KeyValuePair
<string,VxSchemaError
> p
in errs
)
46 WVFAIL("Shouldn't happen: couldn't find error to return");
51 VxSchemaErrors
VxPutSchema(VxSchema schema
, VxPutOpts opts
)
53 log
.print(" + VxPutSchema\n");
55 return dbus
.Put(schema
, null, opts
);
58 [Test
, Category("Schemamatic"), Category("GetSchemaChecksums")]
59 public void TestProcedureChecksums()
61 try { VxExec("drop procedure Func1"); }
catch { }
62 try { VxExec("drop procedure EncFunc"); }
catch { }
64 VxSchemaChecksums sums
;
65 sums
= dbus
.GetChecksums();
68 log
.print("Found entries:");
69 foreach (KeyValuePair
<string,VxSchemaChecksum
> p
in sums
)
72 //WVPASSEQ(sums.Count, 0);
74 string msg1
= "Hello, world, this is Func1!";
75 string msg2
= "Hello, world, this is Func2!";
77 WVASSERT(VxExec("create procedure Func1 as select '" + msg1
+ "'"));
78 WVASSERT(VxScalar("exec Func1", out outmsg
));
79 WVPASSEQ(msg1
, (string)outmsg
);
81 sums
= dbus
.GetChecksums();
83 WVASSERT(sums
.ContainsKey("Procedure/Func1"));
84 WVPASSEQ(sums
["Procedure/Func1"].checksums
.Count(), 1);
85 WVPASSEQ(sums
["Procedure/Func1"].checksums
.First(), 0x55F9D9E3);
87 WVASSERT(VxExec("create procedure EncFunc with encryption as select '" +
90 WVASSERT(VxScalar("exec EncFunc", out outmsg
));
91 WVPASSEQ(msg2
, (string)outmsg
);
93 sums
= dbus
.GetChecksums();
94 //WVPASSEQ(sums.Count, 2);
96 WVASSERT(sums
.ContainsKey("Procedure/Func1"));
97 WVASSERT(sums
.ContainsKey("Procedure-Encrypted/EncFunc"));
98 WVPASSEQ(sums
["Procedure/Func1"].checksums
.Count(), 1);
99 WVPASSEQ(sums
["Procedure-Encrypted/EncFunc"].checksums
.Count(), 1);
100 WVPASSEQ(sums
["Procedure/Func1"].checksums
.First(), 0x55F9D9E3);
101 WVPASSEQ(sums
["Procedure-Encrypted/EncFunc"].checksums
.First(), 0xE5E9304F);
103 WVASSERT(VxExec("drop procedure EncFunc"));
105 sums
= dbus
.GetChecksums();
106 //WVPASSEQ(sums.Count, 1);
108 WVASSERT(sums
.ContainsKey("Procedure/Func1"));
109 WVFAIL(sums
.ContainsKey("Procedure/EncFunc"));
110 WVPASSEQ(sums
["Procedure/Func1"].checksums
.Count(), 1);
111 WVPASSEQ(sums
["Procedure/Func1"].checksums
.First(), 0x55F9D9E3);
113 WVASSERT(VxExec("drop procedure Func1"));
116 [Test
, Category("Schemamatic"), Category("GetSchemaChecksums")]
117 public void TestTableChecksums()
119 SchemaCreator sc
= new SchemaCreator(this);
122 VxSchemaChecksums sums
;
123 sums
= dbus
.GetChecksums();
125 // Three columns gives us three checksums
126 WVPASSEQ(sums
["Table/Tab1"].checksums
.Count(), 3);
127 WVPASSEQ(sums
["Table/Tab1"].checksums
.ElementAt(0), 0xE8634548)
128 WVPASSEQ(sums
["Table/Tab1"].checksums
.ElementAt(1), 0xA5F77357)
129 WVPASSEQ(sums
["Table/Tab1"].checksums
.ElementAt(2), 0xE50EE702)
131 WVASSERT(VxExec("drop table Tab1"));
136 [Test
, Category("Schemamatic"), Category("GetSchemaChecksums")]
137 public void TestIndexChecksums()
139 try { VxExec("drop table Tab1"); }
catch { }
140 string query
= "CREATE TABLE [Tab1] (\n" +
141 "\t[f1] [int] NOT NULL PRIMARY KEY,\n" +
142 "\t[f2] [money] NULL,\n" +
143 "\t[f3] [varchar] (80) NULL);\n\n";
144 WVASSERT(VxExec(query
));
146 query
= "CREATE INDEX [Index1] ON [Tab1] (f1)";
147 WVASSERT(VxExec(query
));
149 query
= "CREATE INDEX [Index2] ON [Tab1] (f1, f2)";
150 WVASSERT(VxExec(query
));
152 VxSchemaChecksums sums
;
153 sums
= dbus
.GetChecksums();
155 WVPASSEQ(sums
["Index/Tab1/Index1"].checksums
.Count(), 1);
156 WVPASSEQ(sums
["Index/Tab1/Index1"].checksums
.First(), 0x62781FDD);
157 // An index on two columns will include two checksums
158 WVPASSEQ(sums
["Index/Tab1/Index2"].checksums
.Count(), 2);
159 WVPASSEQ(sums
["Index/Tab1/Index2"].checksums
.ElementAt(0), 0x603EA184);
160 WVPASSEQ(sums
["Index/Tab1/Index2"].checksums
.ElementAt(1), 0x8FD2C903);
162 WVASSERT(VxExec("drop table Tab1"));
165 [Test
, Category("Schemamatic"), Category("GetSchemaChecksums")]
166 public void TestXmlSchemaChecksums()
168 SchemaCreator sc
= new SchemaCreator(this);
169 WVASSERT(VxExec(sc
.xmlq
));
171 VxSchemaChecksums sums
;
172 sums
= dbus
.GetChecksums();
174 WVPASSEQ(sums
["XMLSchema/TestSchema"].checksums
.Count(), 1);
175 WVPASSEQ(sums
["XMLSchema/TestSchema"].checksums
.First(), 4105357156);
177 WVASSERT(VxExec("drop xml schema collection TestSchema"));
182 [Test
, Category("Schemamatic"), Category("GetSchema")]
183 public void TestGetProcSchema()
185 try { VxExec("drop procedure [Func1!]"); }
catch { }
186 try { VxExec("drop procedure [Func2]"); }
catch { }
188 string msg1
= "Hello, world, this is Func1!";
189 string msg2
= "Hello, world, this is Func2!";
190 string fmt
= "create procedure [{0}] {1} as select '{2}'";
191 string query1
= String
.Format(fmt
, "Func1!", "", msg1
);
192 string query2
= String
.Format(fmt
, "Func2", "with encryption", msg2
);
194 WVASSERT(VxExec(query1
));
195 WVASSERT(VxScalar("exec [Func1!]", out outmsg
));
196 WVPASSEQ(msg1
, (string)outmsg
);
198 WVASSERT(VxExec(query2
));
199 WVASSERT(VxScalar("exec [Func2]", out outmsg
));
200 WVPASSEQ(msg2
, (string)outmsg
);
202 // Check that the query limiting works. Also test that the evil
203 // character cleansing works (turning bad characters into !s)
204 VxSchema schema
= dbus
.Get("Procedure/Func1é");
205 WVPASSEQ(schema
.Count
, 1);
207 WVASSERT(schema
.ContainsKey("Procedure/Func1!"));
208 WVPASSEQ(schema
["Procedure/Func1!"].name
, "Func1!");
209 WVPASSEQ(schema
["Procedure/Func1!"].type
, "Procedure");
210 WVPASSEQ(schema
["Procedure/Func1!"].encrypted
, false);
211 WVPASSEQ(schema
["Procedure/Func1!"].text
, query1
);
213 schema
= dbus
.Get("Func1é");
214 WVPASSEQ(schema
.Count
, 1);
216 WVASSERT(schema
.ContainsKey("Procedure/Func1!"));
217 WVPASSEQ(schema
["Procedure/Func1!"].name
, "Func1!");
218 WVPASSEQ(schema
["Procedure/Func1!"].type
, "Procedure");
219 WVPASSEQ(schema
["Procedure/Func1!"].encrypted
, false);
220 WVPASSEQ(schema
["Procedure/Func1!"].text
, query1
);
222 // Also check that unlimited queries get everything
224 WVASSERT(schema
.Count
>= 2);
226 WVASSERT(schema
.ContainsKey("Procedure/Func1!"));
227 WVPASSEQ(schema
["Procedure/Func1!"].name
, "Func1!");
228 WVPASSEQ(schema
["Procedure/Func1!"].type
, "Procedure");
229 WVPASSEQ(schema
["Procedure/Func1!"].encrypted
, false);
230 WVPASSEQ(schema
["Procedure/Func1!"].text
, query1
);
232 WVASSERT(schema
.ContainsKey("Procedure-Encrypted/Func2"));
233 WVPASSEQ(schema
["Procedure-Encrypted/Func2"].name
, "Func2");
234 WVPASSEQ(schema
["Procedure-Encrypted/Func2"].type
, "Procedure");
235 WVPASSEQ(schema
["Procedure-Encrypted/Func2"].encrypted
, true);
236 // FIXME: Can't yet retrieve the contents of encrypted functions
237 //WVPASSEQ(schema["Procedure-Encrypted/Func2"].text, query2);
239 WVASSERT(VxExec("drop procedure [Func1!]"));
240 WVASSERT(VxExec("drop procedure [Func2]"));
243 [Test
, Category("Schemamatic"), Category("GetSchema")]
244 public void TestGetIndexSchema()
246 SchemaCreator sc
= new SchemaCreator(this);
249 // Check that the query limiting works
250 VxSchema schema
= dbus
.Get("Index/Tab1/Idx1");
251 WVPASSEQ(schema
.Count
, 1);
253 WVASSERT(schema
.ContainsKey("Index/Tab1/Idx1"));
254 WVPASSEQ(schema
["Index/Tab1/Idx1"].name
, "Tab1/Idx1");
255 WVPASSEQ(schema
["Index/Tab1/Idx1"].type
, "Index");
256 WVPASSEQ(schema
["Index/Tab1/Idx1"].encrypted
, false);
257 WVPASSEQ(schema
["Index/Tab1/Idx1"].text
.Length
, sc
.idx1q
.Length
);
258 WVPASSEQ(schema
["Index/Tab1/Idx1"].text
, sc
.idx1q
);
260 // Now get everything, since we don't know the primary key's name
262 WVASSERT(schema
.Count
>= 2);
264 WVASSERT(schema
.ContainsKey("Index/Tab1/Idx1"));
265 WVPASSEQ(schema
["Index/Tab1/Idx1"].name
, "Tab1/Idx1");
266 WVPASSEQ(schema
["Index/Tab1/Idx1"].type
, "Index");
267 WVPASSEQ(schema
["Index/Tab1/Idx1"].encrypted
, false);
268 WVPASSEQ(schema
["Index/Tab1/Idx1"].text
.Length
, sc
.idx1q
.Length
);
269 WVPASSEQ(schema
["Index/Tab1/Idx1"].text
, sc
.idx1q
);
271 CheckForPrimaryKey(schema
, "Tab1");
276 [Test
, Category("Schemamatic"), Category("GetSchema")]
277 public void TestGetXmlSchemas()
279 SchemaCreator sc
= new SchemaCreator(this);
281 try { VxExec("drop xml schema collection TestSchema"); }
catch { }
282 try { VxExec("drop xml schema collection TestSchema2"); }
catch { }
284 string query1
= sc
.xmlq
;
285 WVASSERT(VxExec(query1
));
287 // Make a long XML Schema, to test the 4000-character chunking
288 string query2
= "\nCREATE XML SCHEMA COLLECTION [dbo].[TestSchema2] AS " +
289 "'<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
290 "<xsd:element name=\"Employee\">" +
291 "<xsd:complexType>" +
292 "<xsd:complexContent>" +
293 "<xsd:restriction base=\"xsd:anyType\">" +
296 while (query2
.Length
< 8000)
298 "<xsd:element name=\"SIN\" type=\"xsd:string\"/>" +
299 "<xsd:element name=\"Name\" type=\"xsd:string\"/>" +
300 "<xsd:element name=\"DateOfBirth\" type=\"xsd:date\"/>" +
301 "<xsd:element name=\"EmployeeType\" type=\"xsd:string\"/>" +
302 "<xsd:element name=\"Salary\" type=\"xsd:long\"/>";
304 query2
+= "</xsd:sequence>" +
305 "</xsd:restriction>" +
306 "</xsd:complexContent>" +
307 "</xsd:complexType>" +
311 WVASSERT(VxExec(query2
));
313 // Test that the query limiting works
314 VxSchema schema
= dbus
.Get("TestSchema");
315 WVPASSEQ(schema
.Count
, 1);
317 WVASSERT(schema
.ContainsKey("XMLSchema/TestSchema"));
318 WVPASSEQ(schema
["XMLSchema/TestSchema"].name
, "TestSchema");
319 WVPASSEQ(schema
["XMLSchema/TestSchema"].type
, "XMLSchema");
320 WVPASSEQ(schema
["XMLSchema/TestSchema"].encrypted
, false);
321 WVPASSEQ(schema
["XMLSchema/TestSchema"].text
, query1
);
323 schema
= dbus
.Get("XMLSchema/TestSchema");
324 WVPASSEQ(schema
.Count
, 1);
326 WVASSERT(schema
.ContainsKey("XMLSchema/TestSchema"));
327 WVPASSEQ(schema
["XMLSchema/TestSchema"].name
, "TestSchema");
328 WVPASSEQ(schema
["XMLSchema/TestSchema"].type
, "XMLSchema");
329 WVPASSEQ(schema
["XMLSchema/TestSchema"].encrypted
, false);
330 WVPASSEQ(schema
["XMLSchema/TestSchema"].text
, query1
);
332 // Also check that unlimited queries get everything
334 WVASSERT(schema
.Count
>= 2)
336 WVASSERT(schema
.ContainsKey("XMLSchema/TestSchema"));
337 WVPASSEQ(schema
["XMLSchema/TestSchema"].name
, "TestSchema");
338 WVPASSEQ(schema
["XMLSchema/TestSchema"].type
, "XMLSchema");
339 WVPASSEQ(schema
["XMLSchema/TestSchema"].encrypted
, false);
340 WVPASSEQ(schema
["XMLSchema/TestSchema"].text
, query1
);
342 WVASSERT(schema
.ContainsKey("XMLSchema/TestSchema2"));
343 WVPASSEQ(schema
["XMLSchema/TestSchema2"].name
, "TestSchema2");
344 WVPASSEQ(schema
["XMLSchema/TestSchema2"].type
, "XMLSchema");
345 WVPASSEQ(schema
["XMLSchema/TestSchema2"].encrypted
, false);
346 WVPASSEQ(schema
["XMLSchema/TestSchema2"].text
, query2
);
348 WVASSERT(VxExec("drop xml schema collection TestSchema"));
349 WVASSERT(VxExec("drop xml schema collection TestSchema2"));
352 [Test
, Category("Schemamatic"), Category("GetSchema")]
353 public void TestGetTableSchema()
355 try { VxExec("drop table Table1"); }
catch { }
356 string query
= "CREATE TABLE [Table1] (\n\t" +
357 "[f1] [int] NOT NULL PRIMARY KEY,\n\t" +
358 "[f2] [money] NULL,\n\t" +
359 "[f3] [varchar] (80) NOT NULL,\n\t" +
360 "[f4] [varchar] (max) DEFAULT 'Default Value' NULL,\n\t" +
361 "[f5] [decimal] (3,2),\n\t" +
362 "[f6] [bigint] NOT NULL IDENTITY(4, 5));\n\n";
363 WVASSERT(VxExec(query
));
365 VxSchema schema
= dbus
.Get();
366 WVASSERT(schema
.Count
>= 2);
368 // Primary keys get returned as indexes, not in the CREATE TABLE
369 string result
= query
.Replace(" PRIMARY KEY", "");
370 // Check that columns default to nullable
371 result
= result
.Replace("[f5] [decimal] (3,2)",
372 "[f5] [decimal] (3,2) NULL");
374 WVASSERT(schema
.ContainsKey("Table/Table1"));
375 WVPASSEQ(schema
["Table/Table1"].name
, "Table1");
376 WVPASSEQ(schema
["Table/Table1"].type
, "Table");
377 WVPASSEQ(schema
["Table/Table1"].encrypted
, false);
378 WVPASSEQ(schema
["Table/Table1"].text
, result
);
380 CheckForPrimaryKey(schema
, "Table1");
382 try { VxExec("drop table Table1"); }
catch { }
385 [Test
, Category("Schemamatic"), Category("DropSchema")]
386 public void TestDropSchema()
388 SchemaCreator sc
= new SchemaCreator(this);
392 VxSchemaChecksums sums
= dbus
.GetChecksums();
394 WVASSERT(sums
.ContainsKey("Index/Tab1/Idx1"));
395 WVASSERT(sums
.ContainsKey("Procedure/Func1"));
396 WVASSERT(sums
.ContainsKey("ScalarFunction/Func2"));
397 WVASSERT(sums
.ContainsKey("Table/Tab1"));
398 WVASSERT(sums
.ContainsKey("Table/Tab2"));
399 WVASSERT(sums
.ContainsKey("XMLSchema/TestSchema"));
401 dbus
.DropSchema("Index/Tab1/Idx1", "Procedure/Func1",
402 "ScalarFunction/Func2", "Table/Tab2", "XMLSchema/TestSchema");
404 sums
= dbus
.GetChecksums();
406 WVASSERT(!sums
.ContainsKey("Index/Tab1/Idx1"));
407 WVASSERT(!sums
.ContainsKey("Procedure/Func1"));
408 WVASSERT(!sums
.ContainsKey("ScalarFunction/Func2"));
409 WVASSERT(sums
.ContainsKey("Table/Tab1"));
410 WVASSERT(!sums
.ContainsKey("Table/Tab2"));
411 WVASSERT(!sums
.ContainsKey("XMLSchema/TestSchema"));
413 VxSchemaErrors errs
= dbus
.DropSchema("Procedure/Func1");
414 WVPASSEQ(errs
.Count
, 1);
415 WVPASSEQ(errs
["Procedure/Func1"].msg
,
416 "Cannot drop the procedure 'Func1', because it does not exist " +
417 "or you do not have permission.");
422 [Test
, Category("Schemamatic"), Category("PutSchema")]
423 public void TestPutSchema()
425 SchemaCreator sc
= new SchemaCreator(this);
427 VxPutOpts no_opts
= VxPutOpts
.None
;
428 WVPASSEQ(VxPutSchema("Table", "Tab1", sc
.tab1q
, no_opts
), null);
429 WVPASSEQ(VxPutSchema("Index", "Tab1/Idx1", sc
.idx1q
, no_opts
), null);
430 WVPASSEQ(VxPutSchema("Procedure", "Func1", sc
.func1q
, no_opts
), null);
431 WVPASSEQ(VxPutSchema("XMLSchema", "TestSchema", sc
.xmlq
, no_opts
), null);
433 VxSchema schema
= dbus
.Get();
435 WVASSERT(schema
.ContainsKey("Index/Tab1/Idx1"));
436 WVPASSEQ(schema
["Index/Tab1/Idx1"].name
, "Tab1/Idx1");
437 WVPASSEQ(schema
["Index/Tab1/Idx1"].type
, "Index");
438 WVPASSEQ(schema
["Index/Tab1/Idx1"].text
, sc
.idx1q
);
439 WVASSERT(schema
.ContainsKey("Procedure/Func1"));
440 WVPASSEQ(schema
["Procedure/Func1"].name
, "Func1");
441 WVPASSEQ(schema
["Procedure/Func1"].type
, "Procedure");
442 WVPASSEQ(schema
["Procedure/Func1"].text
, sc
.func1q
);
443 WVASSERT(schema
.ContainsKey("Table/Tab1"));
444 WVPASSEQ(schema
["Table/Tab1"].name
, "Tab1");
445 WVPASSEQ(schema
["Table/Tab1"].type
, "Table");
446 WVPASSEQ(schema
["Table/Tab1"].text
, sc
.tab1q_nopk
);
447 WVASSERT(schema
.ContainsKey("XMLSchema/TestSchema"));
448 WVPASSEQ(schema
["XMLSchema/TestSchema"].name
, "TestSchema");
449 WVPASSEQ(schema
["XMLSchema/TestSchema"].type
, "XMLSchema");
450 WVPASSEQ(schema
["XMLSchema/TestSchema"].text
, sc
.xmlq
);
452 string tab1q2
= "CREATE TABLE [Tab1] (\n\t" +
453 "[f4] [binary] (1) NOT NULL);\n\n";
455 VxSchemaError err
= VxPutSchema("Table", "Tab1", tab1q2
, no_opts
);
457 WVPASSEQ(err
.key
, "Table/Tab1");
459 "There is already an object named 'Tab1' in the database.");
460 WVPASSEQ(err
.errnum
, 2714);
462 schema
= dbus
.Get("Table/Tab1");
463 WVPASSEQ(schema
["Table/Tab1"].name
, "Tab1");
464 WVPASSEQ(schema
["Table/Tab1"].type
, "Table");
465 WVPASSEQ(schema
["Table/Tab1"].text
, sc
.tab1q_nopk
);
467 WVPASSEQ(VxPutSchema("Table", "Tab1", tab1q2
, VxPutOpts
.Destructive
),
470 schema
= dbus
.Get("Table/Tab1");
471 WVPASSEQ(schema
["Table/Tab1"].name
, "Tab1");
472 WVPASSEQ(schema
["Table/Tab1"].type
, "Table");
473 WVPASSEQ(schema
["Table/Tab1"].text
, tab1q2
);
475 string msg2
= "This is definitely not the Func1 you thought you knew.";
476 string func1q2
= "create procedure Func1 as select '" + msg2
+ "'";
477 WVPASSEQ(VxPutSchema("Procedure", "Func1", func1q2
, no_opts
), null);
479 schema
= dbus
.Get("Procedure/Func1");
480 WVPASSEQ(schema
["Procedure/Func1"].name
, "Func1");
481 WVPASSEQ(schema
["Procedure/Func1"].type
, "Procedure");
482 WVPASSEQ(schema
["Procedure/Func1"].text
, func1q2
);
487 [Test
, Category("Schemamatic"), Category("SchemaData")]
488 public void TestSchemaData()
490 SchemaCreator sc
= new SchemaCreator(this);
492 WVPASSEQ(VxPutSchema("Table", "Tab1", sc
.tab1q
, VxPutOpts
.None
), null);
494 List
<string> inserts
= new List
<string>();
495 for (int ii
= 0; ii
< 22; ii
++)
497 inserts
.Add(String
.Format("INSERT INTO Tab1 ([f1],[f2],[f3]) " +
498 "VALUES ({0},{1},'{2}');\n",
499 ii
, ii
+ ".3400", "Hi" + ii
));
502 inserts
.Add("INSERT INTO Tab1 ([f1],[f2],[f3]) " +
503 "VALUES (100,NULL,'');\n");
504 inserts
.Add("INSERT INTO Tab1 ([f1],[f2],[f3]) " +
505 "VALUES (101,NULL," +
506 "'This string''s good for \"testing\" escaping, isn''t it?');\n");
508 foreach (string ins
in inserts
)
509 WVASSERT(VxExec(ins
));
511 WVPASSEQ(dbus
.GetSchemaData("Tab1", 0, ""), inserts
.Join(""));
513 VxExec("drop table Tab1");
516 WVEXCEPT(dbus
.GetSchemaData("Tab1", 0, ""));
517 } catch (Wv
.Test
.WvAssertionFailure e
) {
519 } catch (System
.Exception e
) {
520 WVPASS(e
is DbusError
);
521 WVPASSEQ(e
.Message
, "vx.db.sqlerror: Invalid object name 'Tab1'.");
522 log
.print(e
.ToString() + "\n");
525 WVPASSEQ(VxPutSchema("Table", "Tab1", sc
.tab1q
, VxPutOpts
.None
), null);
527 WVPASSEQ(dbus
.GetSchemaData("Tab1", 0, ""), "");
529 dbus
.PutSchemaData("Tab1", inserts
.Join(""), 0);
530 WVPASSEQ(dbus
.GetSchemaData("Tab1", 0, ""), inserts
.Join(""));
532 WVPASSEQ(dbus
.GetSchemaData("Tab1", 0, "f1 = 11"),
533 "INSERT INTO Tab1 ([f1],[f2],[f3]) VALUES (11,11.3400,'Hi11');\n");
538 [Test
, Category("Schemamatic"), Category("VxSchemaDiff")]
539 public void TestChecksumDiff()
541 VxSchemaChecksums srcsums
= new VxSchemaChecksums();
542 VxSchemaChecksums goalsums
= new VxSchemaChecksums();
543 VxSchemaChecksums emptysums
= new VxSchemaChecksums();
545 srcsums
.AddSum("XMLSchema/secondxml", 2);
546 srcsums
.AddSum("XMLSchema/firstxml", 1);
547 srcsums
.AddSum("Index/Tab1/ConflictIndex", 3);
548 srcsums
.AddSum("Table/HarmonyTable", 6);
550 goalsums
.AddSum("Table/NewTable", 3);
551 goalsums
.AddSum("Procedure/NewFunc", 4);
552 goalsums
.AddSum("Index/Tab1/ConflictIndex", 5);
553 goalsums
.AddSum("Table/HarmonyTable", 6);
555 VxSchemaDiff diff
= new VxSchemaDiff(srcsums
, goalsums
);
557 string expected
= "- XMLSchema/firstxml\n" +
558 "- XMLSchema/secondxml\n" +
559 "+ Table/NewTable\n" +
560 "* Index/Tab1/ConflictIndex\n" +
561 "+ Procedure/NewFunc\n";
562 WVPASSEQ(diff
.ToString(), expected
);
564 // Check that the internal order matches the string's order.
565 WVPASSEQ(diff
.ElementAt(0).Key
, "XMLSchema/firstxml");
566 WVPASSEQ(diff
.ElementAt(1).Key
, "XMLSchema/secondxml");
567 WVPASSEQ(diff
.ElementAt(2).Key
, "Table/NewTable");
568 WVPASSEQ(diff
.ElementAt(3).Key
, "Index/Tab1/ConflictIndex");
569 WVPASSEQ(diff
.ElementAt(4).Key
, "Procedure/NewFunc");
571 // Check that a comparison with an empty set of sums returns the other
573 diff
= new VxSchemaDiff(srcsums
, emptysums
);
574 expected
= "- XMLSchema/firstxml\n" +
575 "- XMLSchema/secondxml\n" +
576 "- Table/HarmonyTable\n" +
577 "- Index/Tab1/ConflictIndex\n";
578 WVPASSEQ(diff
.ToString(), expected
);
580 diff
= new VxSchemaDiff(emptysums
, goalsums
);
581 expected
= "+ Table/HarmonyTable\n" +
582 "+ Table/NewTable\n" +
583 "+ Index/Tab1/ConflictIndex\n" +
584 "+ Procedure/NewFunc\n";
585 WVPASSEQ(diff
.ToString(), expected
);
588 public void TestApplySchemaDiff(ISchemaBackend backend
)
590 log
.print("In TestApplySchemaDiff({0})\n", backend
.GetType().ToString());
591 SchemaCreator sc
= new SchemaCreator(this);
594 string msg2
= "Hello, world, this used to be Func1!";
595 string func1q2
= "create procedure Func1 as select '" + msg2
+ "'\n";
597 VxSchema origschema
= dbus
.Get();
598 VxSchemaChecksums origsums
= dbus
.GetChecksums();
599 VxSchema newschema
= new VxSchema(origschema
);
600 VxSchemaChecksums newsums
= new VxSchemaChecksums(origsums
);
602 // Don't bother putting the data again if we're talking to dbus:
603 // we already snuck it in the back door.
605 backend
.Put(origschema
, origsums
, VxPutOpts
.None
);
607 VxSchemaChecksums diffsums
= new VxSchemaChecksums(newsums
);
609 newschema
["Procedure/Func1"].text
= func1q2
;
610 newsums
.AddSum("Procedure/Func1", 123);
611 newsums
.Remove("XMLSchema/TestSchema");
612 origsums
.Remove("Index/Tab1/Idx1");
614 VxSchemaDiff diff
= new VxSchemaDiff(origsums
, newsums
);
615 using (IEnumerator
<KeyValuePair
<string,VxDiffType
>> iter
=
616 diff
.GetEnumerator())
618 WVPASS(iter
.MoveNext());
619 WVPASSEQ(iter
.Current
.Key
, "XMLSchema/TestSchema");
620 WVPASSEQ((char)iter
.Current
.Value
, (char)VxDiffType
.Remove
);
621 WVPASS(iter
.MoveNext());
622 WVPASSEQ(iter
.Current
.Key
, "Index/Tab1/Idx1");
623 WVPASSEQ((char)iter
.Current
.Value
, (char)VxDiffType
.Add
);
624 WVPASS(iter
.MoveNext());
625 WVPASSEQ(iter
.Current
.Key
, "Procedure/Func1");
626 WVPASSEQ((char)iter
.Current
.Value
, (char)VxDiffType
.Change
);
627 WVFAIL(iter
.MoveNext());
630 VxSchema diffschema
= newschema
.GetDiffElements(diff
);
631 WVPASSEQ(diffschema
["XMLSchema/TestSchema"].type
, "XMLSchema");
632 WVPASSEQ(diffschema
["XMLSchema/TestSchema"].name
, "TestSchema");
633 WVPASSEQ(diffschema
["XMLSchema/TestSchema"].text
, "");
634 WVPASSEQ(diffschema
["Index/Tab1/Idx1"].type
, "Index");
635 WVPASSEQ(diffschema
["Index/Tab1/Idx1"].name
, "Tab1/Idx1");
636 WVPASSEQ(diffschema
["Index/Tab1/Idx1"].text
, sc
.idx1q
);
637 WVPASSEQ(diffschema
["Procedure/Func1"].type
, "Procedure");
638 WVPASSEQ(diffschema
["Procedure/Func1"].name
, "Func1");
639 WVPASSEQ(diffschema
["Procedure/Func1"].text
, func1q2
);
641 VxSchemaErrors errs
= backend
.Put(diffschema
, diffsums
, VxPutOpts
.None
);
642 WVPASSEQ(errs
.Count
, 0);
644 VxSchema updated
= backend
.Get(null);
645 WVASSERT(!updated
.ContainsKey("XMLSchema/TestSchema"));
646 WVPASSEQ(updated
["Index/Tab1/Idx1"].text
,
647 newschema
["Index/Tab1/Idx1"].text
);
648 WVPASSEQ(updated
["Procedure/Func1"].text
,
649 newschema
["Procedure/Func1"].text
);
650 WVPASSEQ(updated
["Table/Tab1"].text
, newschema
["Table/Tab1"].text
);
655 [Test
, Category("Schemamatic"), Category("PutSchema")]
656 public void TestApplySchemaDiff()
658 log
.print("Testing applying diffs through DBus");
659 TestApplySchemaDiff(dbus
);
661 log
.print("Testing applying diffs to the disk");
663 string tmpdir
= GetTempDir();
666 Directory
.CreateDirectory(tmpdir
);
667 VxDiskSchema disk
= new VxDiskSchema(tmpdir
);
669 TestApplySchemaDiff(disk
);
673 Directory
.Delete(tmpdir
, true);
674 WVPASS(!Directory
.Exists(tmpdir
));
678 [Test
, Category("Schemamatic"), Category("PutSchema")]
679 public void TestPutSchemaErrors()
681 SchemaCreator sc
= new SchemaCreator(this);
683 // FIXME: Test with all the SchemaCreator elements
684 WVASSERT(VxExec(sc
.tab1q
));
685 WVASSERT(VxExec(sc
.tab2q
));
687 VxSchema schema
= dbus
.Get();
688 VxPutOpts no_opts
= VxPutOpts
.None
;
689 VxSchemaErrors errs
= VxPutSchema(schema
, no_opts
);
691 log
.print("Results: [\n{0}]\n", errs
.Join("'\n'"));
692 WVPASSEQ(errs
.Count
, 2);
693 WVPASSEQ(errs
["Table/Tab1"].key
, "Table/Tab1");
694 WVPASSEQ(errs
["Table/Tab1"].msg
,
695 "There is already an object named 'Tab1' in the database.");
696 WVPASSEQ(errs
["Table/Tab1"].errnum
, 2714);
697 WVPASSEQ(errs
["Table/Tab2"].key
, "Table/Tab2");
698 WVPASSEQ(errs
["Table/Tab2"].msg
,
699 "There is already an object named 'Tab2' in the database.");
700 WVPASSEQ(errs
["Table/Tab2"].errnum
, 2714);
705 [Test
, Category("Schemamatic"), Category("PutSchema")]
706 public void TestPutSchemaRetry()
708 try { VxExec("drop view View1"); }
catch { }
709 try { VxExec("drop view View2"); }
catch { }
710 try { VxExec("drop view View3"); }
catch { }
711 try { VxExec("drop view View4"); }
catch { }
713 // Create the views in the wrong order, so it'll take a few tries
714 // to get them all working. The server seems to sort them
715 // alphabetically when it runs them, though this isn't a guarantee.
716 string view1q
= "create view View1 as select * from View2";
717 string view2q
= "create view View2 as select * from View3";
718 string view3q
= "create view View3 as select * from View4";
719 string view4q
= "create view View4(viewcol1) as select 42";
721 VxSchema schema
= new VxSchema();
722 schema
.Add("View", "View1", view1q
, false);
723 schema
.Add("View", "View2", view2q
, false);
724 schema
.Add("View", "View3", view3q
, false);
725 schema
.Add("View", "View4", view4q
, false);
727 VxSchemaErrors errs
= VxPutSchema(schema
, VxPutOpts
.NoRetry
);
729 WVPASSEQ(errs
.Count
, 3);
730 WVPASSEQ(errs
["View/View1"].key
, "View/View1");
731 WVPASSEQ(errs
["View/View2"].key
, "View/View2");
732 WVPASSEQ(errs
["View/View3"].key
, "View/View3");
733 WVPASSEQ(errs
["View/View1"].msg
, "Invalid object name 'View2'.");
734 WVPASSEQ(errs
["View/View2"].msg
, "Invalid object name 'View3'.");
735 WVPASSEQ(errs
["View/View3"].msg
, "Invalid object name 'View4'.");
736 WVPASSEQ(errs
["View/View1"].errnum
, 208);
737 WVPASSEQ(errs
["View/View2"].errnum
, 208);
738 WVPASSEQ(errs
["View/View3"].errnum
, 208);
740 try { VxExec("drop view View4"); }
catch { }
741 errs
= VxPutSchema(schema
, VxPutOpts
.None
);
742 WVPASSEQ(errs
.Count
, 0);
745 WVASSERT(VxScalar("select viewcol1 from View1;", out result
));
746 WVPASSEQ((int)result
, 42);
748 try { VxExec("drop view View1"); }
catch { }
749 try { VxExec("drop view View2"); }
catch { }
750 try { VxExec("drop view View3"); }
catch { }
751 try { VxExec("drop view View4"); }
catch { }
754 // Make sure we can insert double-quoted strings, i.e. that
755 // the database has done a "set quoted_identifiers off"
756 [Test
, Category("Schemamatic"), Category("PutSchema")]
757 public void TestQuotedIdentifiers()
759 try { VxExec("drop procedure Proc1"); }
catch { }
761 string quote_proc
= "create procedure Proc1 as " +
762 "select \"I'm a double-quoted string!\"\n";
763 VxSchema schema
= new VxSchema();
764 schema
.Add("Procedure", "Proc1", quote_proc
, false);
766 VxSchemaErrors errs
= VxPutSchema(schema
, VxPutOpts
.None
);
768 WVPASSEQ(errs
.Count
, 0);
770 try { VxExec("drop procedure Proc1"); }
catch { }
773 public static void Main()