1#!/usr/local/bin/lua5.1
2-- See Copyright Notice in license.html
3-- $Id: test.lua,v 1.52 2008/06/30 10:43:03 blumf Exp $
4
5TOTAL_FIELDS = 40
6TOTAL_ROWS = 40 --unused
7
8DEFINITION_STRING_TYPE_NAME = "text"
9QUERYING_STRING_TYPE_NAME = "text"
10
11CREATE_TABLE_RETURN_VALUE = 0
12DROP_TABLE_RETURN_VALUE = 0
13
14MSG_CURSOR_NOT_CLOSED = "cursor was not automatically closed by fetch"
15
16CHECK_GETCOL_INFO_TABLES = true
17
18---------------------------------------------------------------------
19if not string.find(_VERSION, " 5.0") then
20	table.getn = assert((loadstring or load)[[return function (t) return #t end]])()
21end
22
23---------------------------------------------------------------------
24-- Creates a table that can handle differing capitalization of field
25-- names
26-- @return A table with altered metatable
27---------------------------------------------------------------------
28local mt = {
29	__index = function(t, i)
30		if type(i) == "string" then
31			return rawget(t, string.upper(i)) or rawget(t, string.lower(i))
32		end
33
34		return rawget(t, i)
35	end
36}
37function fetch_table ()
38	return setmetatable({}, mt)
39end
40
41---------------------------------------------------------------------
42-- Produces a SQL statement which completely erases a table.
43-- @param table_name String with the name of the table.
44-- @return String with SQL statement.
45---------------------------------------------------------------------
46function sql_erase_table (table_name)
47	return string.format ("delete from %s", table_name)
48end
49
50---------------------------------------------------------------------
51-- checks for a value and throw an error if it is invalid.
52---------------------------------------------------------------------
53function assert2 (expected, value, msg)
54	if not msg then
55		msg = ''
56	else
57		msg = msg..'\n'
58	end
59	return assert (value == expected,
60		msg.."wrong value ("..tostring(value).." instead of "..
61		tostring(expected)..")")
62end
63
64---------------------------------------------------------------------
65-- Shallow compare of two tables
66---------------------------------------------------------------------
67function table_compare(t1, t2)
68	if t1 == t2 then return true; end
69
70	for i, v in pairs(t1) do
71		if t2[i] ~= v then return false; end
72	end
73
74	for i, v in pairs(t2) do
75		if t1[i] ~= v then return false; end
76	end
77
78	return true
79end
80
81---------------------------------------------------------------------
82-- object test.
83---------------------------------------------------------------------
84function test_object (obj, objmethods)
85	-- checking object type.
86	assert2 (true, type(obj) == "userdata" or type(obj) == "table", "incorrect object type")
87
88	-- trying to get metatable.
89	assert2 ("LuaSQL: you're not allowed to get this metatable",
90		getmetatable(obj), "error permitting access to object's metatable")
91	-- trying to set metatable.
92	assert2 (false, pcall (setmetatable, ENV, {}))
93	-- checking existence of object's methods.
94	for i = 1, table.getn (objmethods) do
95		local method = obj[objmethods[i]]
96		assert2 ("function", type(method))
97		assert2 (false, pcall (method), "no 'self' parameter accepted")
98	end
99	return obj
100end
101
102ENV_METHODS = { "close", "connect", }
103ENV_OK = function (obj)
104	return test_object (obj, ENV_METHODS)
105end
106CONN_METHODS = { "close", "commit", "execute", "rollback", "setautocommit", }
107CONN_OK = function (obj)
108	return test_object (obj, CONN_METHODS)
109end
110CUR_METHODS = { "close", "fetch", "getcolnames", "getcoltypes", }
111CUR_OK = function (obj)
112	return test_object (obj, CUR_METHODS)
113end
114
115function checkUnknownDatabase(ENV)
116	assert2 (nil, ENV:connect ("/unknown-data-base"), "this should be an error")
117end
118
119---------------------------------------------------------------------
120-- basic checking test.
121---------------------------------------------------------------------
122function basic_test ()
123	-- Check environment object.
124	ENV = ENV_OK (luasql[driver] ())
125	assert2 (true, ENV:close(), "couldn't close environment")
126	-- trying to connect with a closed environment.
127	assert2 (false, pcall (ENV.connect, ENV, datasource, username, password),
128		"error connecting with a closed environment")
129	-- it is ok to close a closed object, but false is returned instead of true.
130	assert2 (false, ENV:close())
131	-- Reopen the environment.
132	ENV = ENV_OK (luasql[driver] ())
133	-- Check connection object.
134	local conn, err = ENV:connect (datasource, username, password)
135	assert (conn, (err or '').." ("..datasource..")")
136	CONN_OK (conn)
137	assert2 (true, conn:close(), "couldn't close connection")
138	-- trying to execute a statement with a closed connection.
139	assert2 (false, pcall (conn.execute, conn, "create table x (c char)"),
140		"error while executing through a closed connection")
141	-- it is ok to close a closed object, but false is returned instead of true.
142	assert2 (false, conn:close())
143	-- Check error situation.
144	checkUnknownDatabase(ENV)
145
146	-- force garbage collection
147	local a = {}
148	setmetatable(a, {__mode="v"})
149	a.ENV = ENV_OK (luasql[driver] ())
150	a.CONN = a.ENV:connect (datasource, username, password)
151	collectgarbage ()
152	collectgarbage ()
153	assert2(nil, a.ENV, "environment not collected")
154	assert2(nil, a.CONN, "connection not collected")
155end
156
157---------------------------------------------------------------------
158-- Build SQL command to create the test table.
159---------------------------------------------------------------------
160function define_table (n)
161	local t = {}
162	for i = 1, n do
163		table.insert (t, "f"..i.." "..DEFINITION_STRING_TYPE_NAME)
164	end
165	return "create table t ("..table.concat (t, ',')..")"
166end
167
168
169---------------------------------------------------------------------
170-- Create a table with TOTAL_FIELDS character fields.
171---------------------------------------------------------------------
172function create_table ()
173	-- Check SQL statements.
174	CONN = CONN_OK (ENV:connect (datasource, username, password))
175	-- Create t.
176	local cmd = define_table(TOTAL_FIELDS)
177	assert2 (CREATE_TABLE_RETURN_VALUE, CONN:execute (cmd))
178end
179
180---------------------------------------------------------------------
181-- Fetch 2 values.
182---------------------------------------------------------------------
183function fetch2 ()
184	-- insert a record.
185	assert2 (1, CONN:execute ("insert into t (f1, f2) values ('b', 'c')"))
186	-- retrieve data.
187	local cur = CUR_OK (CONN:execute ("select f1, f2, f3 from t"))
188	-- check data.
189	local f1, f2, f3 = cur:fetch()
190	assert2 ('b', f1)
191	assert2 ('c', f2)
192	assert2 (nil, f3)
193	assert2 (nil, cur:fetch())
194	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
195	assert2 (false, cur:close())
196	-- insert a second record.
197	assert2 (1, CONN:execute ("insert into t (f1, f2) values ('d', 'e')"))
198	cur = CUR_OK (CONN:execute ("select f1, f2, f3 from t order by f1"))
199	local f1, f2, f3 = cur:fetch()
200	assert2 ('b', f1, f2)	-- f2 can be an error message
201	assert2 ('c', f2)
202	assert2 (nil, f3)
203	f1, f2, f3 = cur:fetch()
204	assert2 ('d', f1, f2)	-- f2 can be an error message
205	assert2 ('e', f2)
206	assert2 (nil, f3)
207	assert2 (nil, cur:fetch())
208	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
209	assert2 (false, cur:close())
210	-- remove records.
211	assert2 (2, CONN:execute ("delete from t where f1 in ('b', 'd')"))
212end
213
214---------------------------------------------------------------------
215-- Test fetch with a new table, reusing a table and with different
216-- indexing.
217---------------------------------------------------------------------
218function fetch_new_table ()
219	-- insert elements.
220	assert2 (1, CONN:execute ("insert into t (f1, f2, f3, f4) values ('a', 'b', 'c', 'd')"))
221	assert2 (1, CONN:execute ("insert into t (f1, f2, f3, f4) values ('f', 'g', 'h', 'i')"))
222	-- retrieve data using a new table.
223	local cur = CUR_OK (CONN:execute ("select f1, f2, f3, f4 from t order by f1"))
224	local row, err = cur:fetch(fetch_table())
225	assert2 (type(row), "table", err)
226	assert2 ('a', row[1])
227	assert2 ('b', row[2])
228	assert2 ('c', row[3])
229	assert2 ('d', row[4])
230	assert2 (nil, row.f1)
231	assert2 (nil, row.f2)
232	assert2 (nil, row.f3)
233	assert2 (nil, row.f4)
234	row, err = cur:fetch(fetch_table())
235	assert (type(row), "table", err)
236	assert2 ('f', row[1])
237	assert2 ('g', row[2])
238	assert2 ('h', row[3])
239	assert2 ('i', row[4])
240	assert2 (nil, row.f1)
241	assert2 (nil, row.f2)
242	assert2 (nil, row.f3)
243	assert2 (nil, row.f4)
244	assert2 (nil, cur:fetch{})
245	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
246	assert2 (false, cur:close())
247
248	-- retrieve data reusing the same table.
249	io.write ("reusing a table...")
250	cur = CUR_OK (CONN:execute ("select f1, f2, f3, f4 from t order by f1"))
251	local row, err = cur:fetch(fetch_table())
252	assert (type(row), "table", err)
253	assert2 ('a', row[1])
254	assert2 ('b', row[2])
255	assert2 ('c', row[3])
256	assert2 ('d', row[4])
257	assert2 (nil, row.f1)
258	assert2 (nil, row.f2)
259	assert2 (nil, row.f3)
260	assert2 (nil, row.f4)
261	row, err = cur:fetch (row)
262	assert (type(row), "table", err)
263	assert2 ('f', row[1])
264	assert2 ('g', row[2])
265	assert2 ('h', row[3])
266	assert2 ('i', row[4])
267	assert2 (nil, row.f1)
268	assert2 (nil, row.f2)
269	assert2 (nil, row.f3)
270	assert2 (nil, row.f4)
271	assert2 (nil, cur:fetch(fetch_table()))
272	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
273	assert2 (false, cur:close())
274
275	-- retrieve data reusing the same table with alphabetic indexes.
276	io.write ("with alpha keys...")
277	cur = CUR_OK (CONN:execute ("select f1, f2, f3, f4 from t order by f1"))
278	local row, err = cur:fetch (fetch_table(), "a")
279	assert (type(row), "table", err)
280	assert2 (nil, row[1])
281	assert2 (nil, row[2])
282	assert2 (nil, row[3])
283	assert2 (nil, row[4])
284	assert2 ('a', row.f1)
285	assert2 ('b', row.f2)
286	assert2 ('c', row.f3)
287	assert2 ('d', row.f4)
288	row, err = cur:fetch (row, "a")
289	assert2 (type(row), "table", err)
290	assert2 (nil, row[1])
291	assert2 (nil, row[2])
292	assert2 (nil, row[3])
293	assert2 (nil, row[4])
294	assert2 ('f', row.f1)
295	assert2 ('g', row.f2)
296	assert2 ('h', row.f3)
297	assert2 ('i', row.f4)
298	assert2 (nil, cur:fetch(row, "a"))
299	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
300	assert2 (false, cur:close())
301
302	-- retrieve data reusing the same table with both indexes.
303	io.write ("with both keys...")
304	cur = CUR_OK (CONN:execute ("select f1, f2, f3, f4 from t order by f1"))
305	local row, err = cur:fetch (fetch_table(), "an")
306	assert (type(row), "table", err)
307	assert2 ('a', row[1])
308	assert2 ('b', row[2])
309	assert2 ('c', row[3])
310	assert2 ('d', row[4])
311	assert2 ('a', row.f1)
312	assert2 ('b', row.f2)
313	assert2 ('c', row.f3)
314	assert2 ('d', row.f4)
315	row, err = cur:fetch (row, "an")
316	assert (type(row), "table", err)
317	assert2 ('f', row[1])
318	assert2 ('g', row[2])
319	assert2 ('h', row[3])
320	assert2 ('i', row[4])
321	assert2 ('f', row.f1)
322	assert2 ('g', row.f2)
323	assert2 ('h', row.f3)
324	assert2 ('i', row.f4)
325	assert2 (nil, cur:fetch(row, "an"))
326	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
327	assert2 (false, cur:close())
328	-- clean the table.
329	assert2 (2, CONN:execute ("delete from t where f1 in ('a', 'f')"))
330end
331
332---------------------------------------------------------------------
333-- Fetch many values
334---------------------------------------------------------------------
335function fetch_many ()
336	-- insert values.
337	local fields, values = "f1", "'v1'"
338	for i = 2, TOTAL_FIELDS do
339		fields = string.format ("%s,f%d", fields, i)
340		values = string.format ("%s,'v%d'", values, i)
341	end
342	local cmd = string.format ("insert into t (%s) values (%s)",
343		fields, values)
344	assert2 (1, CONN:execute (cmd))
345	-- fetch values (without a table).
346	local cur = CUR_OK (CONN:execute ("select * from t where f1 = 'v1'"))
347	local row = { cur:fetch () }
348	assert2 ("string", type(row[1]), "error while trying to fetch many values (without a table)")
349	for i = 1, TOTAL_FIELDS do
350		assert2 ('v'..i, row[i])
351	end
352	assert2 (nil, cur:fetch (row))
353	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
354	-- fetch values (with a table and default indexing).
355	io.write ("with a table...")
356	local cur = CUR_OK (CONN:execute ("select * from t where f1 = 'v1'"))
357	local row = cur:fetch(fetch_table())
358	assert2 ("string", type(row[1]), "error while trying to fetch many values (default indexing)")
359	for i = 1, TOTAL_FIELDS do
360		assert2 ('v'..i, row[i])
361	end
362	assert2 (nil, cur:fetch (row))
363	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
364	-- fetch values (with numbered indexes on a table).
365	io.write ("with numbered keys...")
366	local cur = CUR_OK (CONN:execute ("select * from t where f1 = 'v1'"))
367	local row = cur:fetch (fetch_table(), "n")
368	assert2 ("string", type(row[1]), "error while trying to fetch many values (numbered indexes)")
369	for i = 1, TOTAL_FIELDS do
370		assert2 ('v'..i, row[i])
371	end
372	assert2 (nil, cur:fetch (row))
373	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
374	-- fetch values (with alphanumeric indexes on a table).
375	io.write ("with alpha keys...")
376	local cur = CUR_OK (CONN:execute ("select * from t where f1 = 'v1'"))
377	local row = cur:fetch (fetch_table(), "a")
378	assert2 ("string", type(row.f1), "error while trying to fetch many values (alphanumeric indexes)")
379	for i = 1, TOTAL_FIELDS do
380		assert2 ('v'..i, row['f'..i])
381	end
382	assert2 (nil, cur:fetch (row))
383	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
384	-- fetch values (with both indexes on a table).
385	io.write ("with both keys...")
386	local cur = CUR_OK (CONN:execute ("select * from t where f1 = 'v1'"))
387	local row = cur:fetch (fetch_table(), "na")
388	assert2 ("string", type(row[1]), "error while trying to fetch many values (both indexes)")
389	assert2 ("string", type(row.f1), "error while trying to fetch many values (both indexes)")
390	for i = 1, TOTAL_FIELDS do
391		assert2 ('v'..i, row[i])
392		assert2 ('v'..i, row['f'..i])
393	end
394	assert2 (nil, cur:fetch (row))
395	assert2 (false, cur:close(), MSG_CURSOR_NOT_CLOSED)
396	-- clean the table.
397	assert2 (1, CONN:execute ("delete from t where f1 = 'v1'"))
398end
399
400---------------------------------------------------------------------
401---------------------------------------------------------------------
402function rollback ()
403	-- begin transaction
404	assert2 (true, CONN:setautocommit (false), "couldn't disable autocommit")
405	-- insert a record and commit the operation.
406	assert2 (1, CONN:execute ("insert into t (f1) values ('a')"))
407	local cur = CUR_OK (CONN:execute ("select count(*) from t"))
408	assert2 (1, tonumber (cur:fetch ()), "Insert failed")
409	assert2 (true, cur:close(), "couldn't close cursor")
410	assert2 (false, cur:close())
411	assert2 (true, CONN:commit(), "couldn't commit transaction")
412	-- insert a record and roll back the operation.
413	assert2 (1, CONN:execute ("insert into t (f1) values ('b')"))
414	local cur = CUR_OK (CONN:execute ("select count(*) from t"))
415	assert2 (2, tonumber (cur:fetch ()), "Insert failed")
416	assert2 (true, cur:close(), "couldn't close cursor")
417	assert2 (false, cur:close())
418	assert2 (true, CONN:rollback (), "couldn't roolback transaction")
419	-- check resulting table with one record.
420	cur = CUR_OK (CONN:execute ("select count(*) from t"))
421	assert2 (1, tonumber(cur:fetch()), "Rollback failed")
422	assert2 (true, cur:close(), "couldn't close cursor")
423	assert2 (false, cur:close())
424	-- delete a record and roll back the operation.
425	assert2 (1, CONN:execute ("delete from t where f1 = 'a'"))
426	cur = CUR_OK (CONN:execute ("select count(*) from t"))
427	assert2 (0, tonumber(cur:fetch()))
428	assert2 (true, cur:close(), "couldn't close cursor")
429	assert2 (false, cur:close())
430	assert2 (true, CONN:rollback (), "couldn't roolback transaction")
431	-- check resulting table with one record.
432	cur = CUR_OK (CONN:execute ("select count(*) from t"))
433	assert2 (1, tonumber(cur:fetch()), "Rollback failed")
434	assert2 (true, cur:close(), "couldn't close cursor")
435	assert2 (false, cur:close())
436--[[
437	-- insert a second record and turn on the auto-commit mode.
438	-- this will produce a rollback on PostgreSQL and a commit on ODBC.
439	-- what to do?
440	assert2 (1, CONN:execute ("insert into t (f1) values ('b')"))
441	cur = CUR_OK (CONN:execute ("select count(*) from t"))
442	assert2 (2, tonumber (cur:fetch ()), "Insert failed")
443	assert2 (true, cur:close(), "couldn't close cursor")
444	assert2 (false, cur:close())
445	assert2 (true, CONN:setautocommit (true), "couldn't enable autocommit")
446	-- check resulting table with one record.
447	cur = CUR_OK (CONN:execute ("select count(*) from t"))
448	assert2 (1, tonumber(cur:fetch()), "Rollback failed")
449	assert2 (true, cur:close(), "couldn't close cursor")
450	assert2 (false, cur:close())
451--]]
452	-- clean the table.
453	assert2 (1, CONN:execute (sql_erase_table"t"))
454	assert2 (true, CONN:commit (), "couldn't commit transaction")
455	assert2 (true, CONN:setautocommit (true), "couldn't enable autocommit")
456	-- check resulting table with no records.
457	cur = CUR_OK (CONN:execute ("select count(*) from t"))
458	assert2 (0, tonumber(cur:fetch()), "Rollback failed")
459	assert2 (true, cur:close(), "couldn't close cursor")
460	assert2 (false, cur:close())
461end
462
463---------------------------------------------------------------------
464-- Get column names and types.
465---------------------------------------------------------------------
466function column_info ()
467	-- insert elements.
468	assert2 (1, CONN:execute ("insert into t (f1, f2, f3, f4) values ('a', 'b', 'c', 'd')"))
469	local cur = CUR_OK (CONN:execute ("select f1,f2,f3,f4 from t"))
470	-- get column information.
471	local names, types = cur:getcolnames(), cur:getcoltypes()
472	assert2 ("table", type(names), "getcolnames failed")
473	assert2 ("table", type(types), "getcoltypes failed")
474	assert2 (4, table.getn(names), "incorrect column names table")
475	assert2 (4, table.getn(types), "incorrect column types table")
476	for i = 1, table.getn(names) do
477		assert2 ("f"..i, string.lower(names[i]), "incorrect column names table")
478		local type_i = types[i]
479		assert (type_i == QUERYING_STRING_TYPE_NAME, "incorrect column types table")
480	end
481	-- check if the tables are being reused.
482	local n2, t2 = cur:getcolnames(), cur:getcoltypes()
483	if CHECK_GETCOL_INFO_TABLES then
484		assert2 (names, n2, "getcolnames is rebuilding the table")
485		assert2 (types, t2, "getcoltypes is rebuilding the table")
486	else
487		assert2 (true, table_compare(names, n2), "getcolnames is inconsistent")
488		assert2 (true, table_compare(types, t2), "getcoltypes is inconsistent")
489	end
490	assert2 (true, cur:close(), "couldn't close cursor")
491	assert2 (false, cur:close())
492	-- clean the table.
493	assert2 (1, CONN:execute ("delete from t where f1 = 'a'"))
494end
495
496---------------------------------------------------------------------
497-- Escaping strings
498---------------------------------------------------------------------
499function escape ()
500	local escaped = CONN:escape"a'b'c'd"
501	assert ("a\\'b\\'c\\'d" == escaped or "a''b''c''d" == escaped)
502
503	local n = 5200
504	local s1 = string.rep("'", n)
505	local s2 = CONN:escape(s1)
506	local s3 = s1:gsub ("'", "\\'")
507	assert (s1:len() == n)
508	assert (s2:len() == 2*n)
509	assert (s2 == s1..s1 or s2 == s3)
510
511	io.write (" escape")
512end
513
514---------------------------------------------------------------------
515---------------------------------------------------------------------
516function check_close()
517	-- an object with references to it can't be closed
518	local cmd = "select * from t"
519	local cur = CUR_OK(CONN:execute (cmd))
520	assert2 (true, cur:close(), "couldn't close cursor")
521
522	-- force garbage collection
523	local a = {}
524	setmetatable(a, {__mode="v"})
525	a.CONN = ENV:connect (datasource, username, password)
526	cur = CUR_OK(a.CONN:execute (cmd))
527
528	collectgarbage ()
529	collectgarbage ()
530	CONN_OK (a.CONN)
531	a.cur = cur
532	a.cur:close()
533	a.CONN:close()
534	cur = nil
535	collectgarbage ()
536	assert2(nil, a.cur, "cursor not collected")
537	collectgarbage ()
538	assert2(nil, a.CONN, "connection not collected")
539
540	-- check cursor integrity after trying to close a connection
541	local conn = CONN_OK (ENV:connect (datasource, username, password))
542	assert2 (1, conn:execute"insert into t (f1) values (1)", "could not insert a new record")
543	local cur = CUR_OK (conn:execute (cmd))
544	local ok, err = pcall (conn.close, conn)
545	CUR_OK (cur)
546	assert (cur:fetch(), "corrupted cursor")
547	cur:close ()
548	conn:close ()
549end
550
551---------------------------------------------------------------------
552---------------------------------------------------------------------
553function drop_table ()
554	assert2 (true, CONN:setautocommit(true), "couldn't enable autocommit")
555	-- Postgres retorns 0, ODBC retorns -1, sqlite returns 1
556	assert2 (DROP_TABLE_RETURN_VALUE, CONN:execute ("drop table t"))
557end
558
559---------------------------------------------------------------------
560---------------------------------------------------------------------
561function close_conn ()
562	assert (true, CONN:close())
563	assert (true, ENV:close())
564end
565
566---------------------------------------------------------------------
567---------------------------------------------------------------------
568function finalization ()
569	-- nothing to do
570end
571
572---------------------------------------------------------------------
573-- Testing Extensions
574---------------------------------------------------------------------
575EXTENSIONS = {
576}
577function extensions_test ()
578	for i, f in ipairs (EXTENSIONS) do
579		f ()
580	end
581end
582
583---------------------------------------------------------------------
584-- Testing numrows method.
585-- This is not a default test, it must be added to the extensions
586-- table to be executed.
587---------------------------------------------------------------------
588function numrows()
589    local cur = CUR_OK(CONN:execute"select * from t")
590    assert2(0,cur:numrows())
591    cur:close()
592
593    -- Inserts one row.
594    assert2 (1, CONN:execute"insert into t (f1) values ('a')", "could not insert a new record")
595    cur = CUR_OK(CONN:execute"select * from t")
596    assert2(1,cur:numrows())
597    cur:close()
598
599    -- Inserts three more rows (total = 4).
600    assert2 (1, CONN:execute"insert into t (f1) values ('b')", "could not insert a new record")
601    assert2 (1, CONN:execute"insert into t (f1) values ('c')", "could not insert a new record")
602    assert2 (1, CONN:execute"insert into t (f1) values ('d')", "could not insert a new record")
603    cur = CUR_OK(CONN:execute"select * from t")
604    assert2(4,cur:numrows())
605	cur:close()
606
607    -- Deletes one row
608    assert2(1, CONN:execute"delete from t where f1 = 'a'", "could not delete the specified row")
609    cur = CUR_OK(CONN:execute"select * from t")
610    assert2(3,cur:numrows())
611    cur:close()
612
613    -- Deletes all rows
614    assert2 (3, CONN:execute (sql_erase_table"t"))
615    cur = CUR_OK(CONN:execute"select * from t")
616    assert2(0,cur:numrows())
617    cur:close()
618
619	io.write (" numrows")
620end
621
622
623---------------------------------------------------------------------
624-- Main
625---------------------------------------------------------------------
626
627if type(arg[1]) ~= "string" then
628	print (string.format ("Usage %s <driver> [<data source> [, <user> [, <password>]]]", arg[0]))
629	os.exit()
630end
631
632driver = arg[1]
633
634-- Loading driver specific functions
635if arg[0] then
636	local path = string.gsub (arg[0], "^(.*%/)[^/]*$", "%1")
637	if path == "test.lua" then
638		path = ""
639	end
640	local file = path..driver..".lua"
641	local f, err = loadfile (file)
642	if not f then
643		print ("LuaSQL test: couldn't find driver-specific test file ("..
644			file..").\nProceeding with general test")
645	else
646		print ("Loading driver-specific test file ("..file..").")
647		f ()
648	end
649end
650
651datasource = arg[2] or DEFAULT_TEST_DATABASE or "luasql-test"
652username = arg[3] or DEFAULT_USERNAME or nil
653password = arg[4] or DEFAULT_PASSWORD or nil
654
655-- Complete set of tests
656tests = {
657	{ "basic checking", basic_test },
658	{ "create table", create_table },
659	{ "fetch two values", fetch2 },
660	{ "fetch new table", fetch_new_table },
661	{ "fetch many", fetch_many },
662	{ "rollback", rollback },
663	{ "get column information", column_info },
664	{ "extensions", extensions_test },
665	{ "close objects", check_close },
666	{ "drop table", drop_table },
667	{ "close connection", close_conn },
668	{ "finalization", finalization },
669}
670
671if string.find(_VERSION, " 5.0") then
672	local init_so, err = loadlib("./"..driver..".so", "luaopen_luasql_"..driver)
673	if init_so then
674		luasql = init_so()
675	else
676		luasql = assert(loadlib("/usr/local/lib/lua/5.0/luasql/"..driver..".so", "luaopen_luasql_"..driver))()
677	end
678else
679	luasql = require ("luasql."..driver)
680end
681assert (luasql, "Could not load driver: no luasql table.")
682io.write (luasql._VERSION.." "..driver)
683if luasql._CLIENTVERSION then
684	io.write (" ("..luasql._CLIENTVERSION..")")
685end
686io.write (" driver test.  "..luasql._COPYRIGHT.."\n")
687
688for i = 1, table.getn (tests) do
689	local t = tests[i]
690	io.write (t[1].." ...")
691	local ok, err = xpcall (t[2], debug.traceback)
692	if not ok then
693		io.write ("\n"..err)
694		io.write"\n... trying to drop test table ..."
695		local ok, err = pcall (drop_table)
696		if not ok then
697			io.write (" failed: "..err)
698		else
699			io.write" OK !\n... and to close the connection ..."
700			local ok, err = pcall (close_conn)
701			if not ok then
702				io.write (" failed: "..err)
703			else
704				io.write" OK !"
705			end
706		end
707		io.write"\nThe test failed!\n"
708		return
709	end
710	io.write (" OK !\n")
711end
712io.write ("The test passed!\n")
713