1#[cfg(test)]
2pub fn test_amount() -> usize {
4 str::parse(&std::env::var("TA").unwrap_or("1".to_string())).unwrap()
5}
6
7#[test]
8fn save_test() {
10 use crate::*;
11
12 let mf = MemFile::new();
13
14 for i in 0..2 {
15 let mut bmap = BuiltinMap::default();
16 standard_builtins(&mut bmap);
17 let bmap = Arc::new(bmap);
18
19 let af = AtomicFile::new(mf.clone(), MemFile::new());
20 let spd = SharedPagedData::new(af);
21 let wapd = spd.new_writer();
22
23 let db = Database::new(wapd, "CREATE SCHEMA test", bmap.clone());
24
25 let mut tr = GenTransaction::default();
26
27 if i == 0 {
28 let sql = "
29CREATE TABLE test.Cust(Name string) GO
30INSERT INTO test.Cust(Name) VALUES ('freddy')
31";
32 db.run(&sql, &mut tr);
33 assert!(db.changed());
34 assert!(db.save() > 0);
35 spd.wait_complete();
36 } else {
37 let sql = "SELECT Name FROM test.Cust";
38 db.run(&sql, &mut tr);
39 assert_eq!(tr.rp.output, b"freddy");
40 }
41 }
42}
43
44#[test]
45fn concurrency() {
46 use crate::*;
47
48 let stg = AtomicFile::new(MemFile::new(), MemFile::new());
49
50 let mut bmap = BuiltinMap::default();
51 standard_builtins(&mut bmap);
52 let bmap = Arc::new(bmap);
53
54 let spd = SharedPagedData::new(stg);
55 let wapd = spd.new_writer();
56 let db = Database::new(wapd, "CREATE SCHEMA test", bmap.clone());
57
58 let nt = 100;
59
60 for i in 0..nt {
62 let mut tr = GenTransaction::default();
63 let sql = format!(
64 "CREATE TABLE test.[T{}](N int) GO INSERT INTO test.[T{}](N) VALUES (0)",
65 i, i
66 );
67 db.run(&sql, &mut tr);
68 assert!(db.save() > 0);
69 }
70
71 let mut rapd = Vec::new();
73 for i in 0..1000 * test_amount() {
74 rapd.push((i, spd.new_reader()));
75 let mut tr = GenTransaction::default();
76 let table = i % nt;
77 let sql = format!("UPDATE test.[T{}] SET N = N + 1 WHERE 1=1", table);
78 db.run(&sql, &mut tr);
79 assert!(db.save() > 0);
80 }
81
82 use rand::Rng;
84 let mut rng = rand::thread_rng();
85 while !rapd.is_empty() {
86 let r = rng.r#gen::<usize>() % rapd.len();
87 let (i, rapd) = rapd.remove(r);
88 let db = Database::new(rapd, "", bmap.clone());
89 let mut tr = GenTransaction::default();
90 let table = rng.r#gen::<usize>() % nt;
91 let sql = format!("SELECT N FROM test.[T{}]", table);
92 db.run(&sql, &mut tr);
93 let expect = i / nt + if i % nt > table { 1 } else { 0 };
94 assert!(tr.rp.output == format!("{}", expect).as_bytes());
95 }
96}
97
98#[test]
99fn rtest() {
100 use crate::*;
101
102 const INITSQL : &str = "
103
104CREATE FN sys.QuoteName( s string ) RETURNS string AS
105BEGIN
106 RETURN '[' | REPLACE( s, ']', ']]' ) | ']'
107END
108
109CREATE FN sys.Dot( schema string, name string ) RETURNS string AS
110BEGIN
111 RETURN sys.QuoteName( schema ) | '.' | sys.QuoteName( name )
112END
113
114CREATE FN sys.TableName( table int ) RETURNS string AS
115BEGIN
116 DECLARE schema int, name string
117 SET schema = Schema, name = Name FROM sys.Table WHERE Id = table
118 IF name = '' RETURN ''
119 SET result = sys.Dot( Name, name ) FROM sys.Schema WHERE Id = schema
120END
121
122CREATE FN sys.DropTable
123( t int ) AS
124/* Note: this should not be called directly, instead use DROP TABLE statement */
125BEGIN
126 /* Delete the rows */
127 EXECUTE( 'DELETE FROM ' | sys.TableName(t) | ' WHERE true' )
128
129 DECLARE id int
130 /* Delete the Index data */
131 FOR id = Id FROM sys.Index WHERE Table = t
132 BEGIN
133 DELETE FROM sys.IndexColumn WHERE Index = id
134 END
135 DELETE FROM sys.Index WHERE Table = t
136 /* Delete the column data */
137 FOR id = Id FROM sys.Column WHERE Table = t
138 BEGIN
139 -- DELETE FROM browse.Column WHERE Id = id
140 END
141 /* Delete other data */
142 -- DELETE FROM browse.Table WHERE Id = t
143 DELETE FROM sys.Column WHERE Table = t
144 DELETE FROM sys.Table WHERE Id = t
145END
146
147CREATE FN sys.ClearTable
148(t int) AS
149BEGIN
150 EXECUTE( 'DELETE FROM ' | sys.TableName(t) | ' WHERE true' )
151END
152
153CREATE SCHEMA rtest
154GO
155CREATE TABLE rtest.Gen(x int)
156GO
157INSERT INTO rtest.Gen(x) VALUES(1)
158GO
159CREATE SCHEMA rtestdata
160GO
161
162CREATE FN rtest.repeat( s string, n int ) RETURNS string AS
163BEGIN
164 WHILE n > 0
165 BEGIN
166 SET result |= s
167 SET n -= 1
168 END
169END
170
171CREATE FN rtest.OneTest() AS
172BEGIN
173 DECLARE rtestdata int
174 SET rtestdata = Id FROM sys.Schema WHERE Name = 'rtestdata'
175
176 DECLARE r int
177 SET r = x FROM rtest.Gen
178 SET r = r * 48271 % 2147483647
179
180 DECLARE sql string, a int
181 SET a = r % 2
182
183 DECLARE tname string
184 SET tname = 't' | ( r / 100 ) % 7
185
186 DECLARE exists string
187 SET exists = ''
188 SET exists = Name FROM sys.Table WHERE Schema = rtestdata AND Name = tname
189
190 SET sql = CASE
191 WHEN r % 20 = 0 THEN 'SELECT VERIFYDB()'
192 WHEN r % 20 = 19 THEN 'SELECT REPACKFILE(-4,'''','''')'
193 WHEN r % 20 = 18 THEN 'SELECT REPACKFILE(-3,'''','''')'
194 WHEN r % 20 = 17 THEN 'SELECT RENUMBER()'
195 WHEN exists = '' THEN
196 CASE WHEN r % 2 =1 THEN 'CREATE TABLE rtestdata.[' | tname | '](x string, y int(5))'
197 ELSE 'CREATE TABLE rtestdata.[' | tname | '](x string, y int(3), z string )'
198 END
199 WHEN r % 5 = 0 THEN 'ALTER TABLE rtestdata.[' | tname | '] ADD [z' | r | '] binary'
200 WHEN r % 21 = 1 THEN 'DROP TABLE rtestdata.[' | tname | ']'
201 WHEN r % 2 = 1 THEN 'INSERT INTO rtestdata.[' | tname | '](x,y) VALUES ( rtest.repeat(''George Gordon Fairbrother Barwood'','|(r % 1000)|'),' | (r % 10) | ')'
202 ELSE 'DELETE FROM rtestdata.[' | tname | '] WHERE y = ' | ( r%15)
203 END
204 SELECT ' sql=' | sql
205 EXECUTE( sql )
206 UPDATE rtest.Gen SET x = r WHERE true
207END
208GO
209";
210
211 let stg = AtomicFile::new(MemFile::new(), MemFile::new());
212
213 let mut bmap = BuiltinMap::default();
214 standard_builtins(&mut bmap);
215 let bmap = Arc::new(bmap);
216
217 let spd = SharedPagedData::new(stg);
218 let wapd = spd.new_writer();
219
220 let db = Database::new(wapd, INITSQL, bmap.clone());
221
222 {
224 }
227
228 for _i in 0..1000 * test_amount() {
229 let mut tr = GenTransaction::default();
230 let sql = "EXEC rtest.OneTest()";
231 db.run(&sql, &mut tr);
232 db.save();
233 let s = std::str::from_utf8(&tr.rp.output).unwrap();
234 if s.len() > 0 {
235 }
237 assert_eq!(tr.get_error(), "");
238 }
239}
240
241#[test]
242fn rollback() {
243 use crate::*;
244
245 let stg = AtomicFile::new(MemFile::new(), MemFile::new());
246
247 let mut bmap = BuiltinMap::default();
248 standard_builtins(&mut bmap);
249 let bmap = Arc::new(bmap);
250
251 let spd = SharedPagedData::new(stg);
252
253 let wapd = spd.new_writer();
254 let db = Database::new(wapd, "", bmap.clone());
255
256 let mut tr = GenTransaction::default();
257 let sql = "
258 CREATE TABLE sys.test(x int)
259 DECLARE sql string SET sql = 'SELECT PARSEINT(''x'')'
260 EXECUTE(sql)
261 ";
262 db.run(&sql, &mut tr);
263}
264
265#[test]
266fn insert_delete() {
267 use crate::*;
268
269 let stg = AtomicFile::new(MemFile::new(), MemFile::new());
270
271 let mut bmap = BuiltinMap::default();
272 standard_builtins(&mut bmap);
273 let bmap = Arc::new(bmap);
274
275 let spd = SharedPagedData::new(stg);
276 let wapd = spd.new_writer();
277 let db = Database::new(wapd, "", bmap.clone());
278
279 let mut tr = GenTransaction::default();
280
281 let sql = format!(
282 "
283 CREATE TABLE sys.test(x int,name string)
284 GO
285 DECLARE @i int
286 WHILE @i < {}
287 BEGIN
288 INSERT INTO sys.test(x,name) VALUES(@i,'Hello World')
289 SET @i += 1
290 END
291 DELETE FROM sys.test WHERE Id % 3 = 1
292 DELETE FROM sys.test WHERE Id % 3 = 2
293 DELETE FROM sys.test WHERE true
294 ",
295 test_amount() * 100000
296 );
297 db.run(&sql, &mut tr);
298 db.save();
299 assert_eq!(tr.get_error(), "");
300}
301
302#[test]
305fn test_date_calc() {
306 use crate::*;
307 const INITSQL: &str = "
308CREATE SCHEMA [date]
309CREATE FN [date].[YearDayToYearMonthDay]( yd int ) RETURNS int AS
310BEGIN
311 DECLARE y int, d int, leap bool, fdm int, m int, dim int
312 SET y = yd / 512
313 SET d = yd % 512 - 1
314 SET leap = date.IsLeapYear( y )
315 -- Jan = 0..30, Feb = 0..27 or 0..28
316 IF NOT leap AND d >= 59 SET d = d + 1
317 SET fdm = CASE
318 WHEN d < 31 THEN 0 -- Jan
319 WHEN d < 60 THEN 31 -- Feb
320 WHEN d < 91 THEN 60 -- Mar
321 WHEN d < 121 THEN 91 -- Apr
322 WHEN d < 152 THEN 121 -- May
323 WHEN d < 182 THEN 152 -- Jun
324 WHEN d < 213 THEN 182 -- Jul
325 WHEN d < 244 THEN 213 -- Aug
326 WHEN d < 274 THEN 244 -- Sep
327 WHEN d < 305 THEN 274 -- Oct
328 WHEN d < 335 THEN 305 -- Nov
329 ELSE 335 -- Dec
330 END
331 SET dim = d - fdm
332 SET m = ( d - dim + 28 ) / 31
333 RETURN date.YearMonthDay( y, m+1, dim+1 )
334END
335
336CREATE FN [date].[DaysToYearDay]( days int ) RETURNS int AS
337BEGIN
338 -- Given a date represented by the number of days since 1 Jan 0000
339 -- calculate a date in Year/Day representation stored as
340 -- year * 512 + day where day is 1..366, the day in the year.
341
342 DECLARE year int, day int, cycle int
343 -- 146097 is the number of the days in a 400 year cycle ( 400 * 365 + 97 leap years )
344 SET cycle = days / 146097
345 SET days = days - 146097 * cycle -- Same as days % 146097
346 SET year = days / 365
347 SET day = days - year * 365 -- Same as days % 365
348 -- Need to adjust day to allow for leap years.
349 -- Leap years are 0, 4, 8, 12 ... 96, not 100, 104 ... not 200... not 300, 400, 404 ... not 500.
350 -- Adjustment as function of y is 0 => 0, 1 => 1, 2 =>1, 3 => 1, 4 => 1, 5 => 2 ..
351 SET day = day - ( year + 3 ) / 4 + ( year + 99 ) / 100 - ( year + 399 ) / 400
352
353 IF day < 0
354 BEGIN
355 SET year -= 1
356 SET day += CASE WHEN date.IsLeapYear( year ) THEN 366 ELSE 365 END
357 END
358 RETURN 512 * ( cycle * 400 + year ) + day + 1
359END
360
361CREATE FN [date].[YearMonthDay]( year int, month int, day int ) RETURNS int AS
362BEGIN
363 RETURN year * 512 + month * 32 + day
364END
365
366CREATE FN [date].[IsLeapYear]( y int ) RETURNS bool AS
367BEGIN
368 RETURN y % 4 = 0 AND ( y % 100 != 0 OR y % 400 = 0 )
369END
370
371CREATE FN [date].[DaysToYearMonthDay]( days int ) RETURNS int AS
372BEGIN
373 RETURN date.YearDayToYearMonthDay( date.DaysToYearDay( days ) )
374END
375
376CREATE FN [date].[test]() AS
377BEGIN
378 DECLARE days int, ymd int
379 WHILE days < 1000
380 BEGIN
381 SET days += 1
382 SET ymd = date.DaysToYearMonthDay(days)
383 END
384END
385";
386
387 let stg = AtomicFile::new(MemFile::new(), MemFile::new());
388
389 let mut bmap = BuiltinMap::default();
390 standard_builtins(&mut bmap);
391 let bmap = Arc::new(bmap);
392
393 let spd = SharedPagedData::new(stg);
394 let wapd = spd.new_writer();
395 let db = Database::new(wapd, INITSQL, bmap.clone());
396
397 {
399 }
402
403 let mut results = Vec::new();
404 for _i in 0..100 {
405 let start = std::time::Instant::now();
406 let mut tr = GenTransaction::default();
407 let sql = "EXEC date.test()";
408 db.run(&sql, &mut tr);
409 results.push(start.elapsed().as_micros() as u64);
410 assert_eq!(tr.get_error(), "");
411 }
412 crate::bench::print_results("date calc test", results);
413}