1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
#simulation of the real icondb.icn
#using the C mysql and postgresql interfaces for Icon 9.4.
#use with cgi.icn (instead of web.icn)
#until loadfuncpp becomes reliable
#WARNING: can only connect to one mysql and one postgresql database at a time
#CS 2008/7/27
link io
#the C interface
procedure _mysqldb(arg[])
return ( _mysqldb := pathload("mysqldb.so","mysqldb") )!arg
end
procedure _postgresqldb(arg[])
return ( _postgresqldb := pathload("postgresqldb.so","postgresqldb") )!arg
end
#simulated external value
record database_handle(connection, c_interface)
#simulated mysql connection procedure
procedure _connectmysql(dbname, user, pwd, host, port)
local connection, result
icondb_error := &null
connection := [dbname, user, pwd]
if put(connection, \host) then put(connection, \port)
result := _mysqldb(connection)
if /result then return database_handle(connection, _mysqldb)
icondb_error := result
fail
end
#simulated postgresql connection procedure
procedure _connectpostgresql(dbname, user, pwd, host, port)
local connection, result
icondb_error := &null
connection := [dbname, user, pwd]
if put(connection, \host) then put(connection, \port)
result := _postgresqldb(connection)
if /result then return database_handle(connection, _postgresqldb)
icondb_error := result
fail
end
global icondb_error
#icondb returns a connection procedure for a known kind of dbms
#which may then be called following the pattern
#dbhandle := connect(dbname, user, pwd, host, port)
#where host and port are optional
procedure icondb(kind)
case kind of {
"mysql" : return _connectmysql
"postgresql" : return _connectpostgresql
default : stop("icondb: unknown dbms\nerror: ", image(kind)) | fail
}
end
procedure dbclose(db)
if type(db) ~== "database_handle" then
stop("dbclose: not a database handle: ", image(db))
icondb_error := &null
db.c_interface()
return
end
procedure dbquery(db, query, constructor)
local result, rec
if type(db) ~== "database_handle" then
stop("dbquery: not a database handle: ", image(db))
case type(constructor) of {
"null" :
&null
"procedure" :
image(constructor) ? {
="record constructor" |
stop("dbquery: not a record constructor: ", image(constructor))
}
default :
stop("dbquery: not a record constructor: ", image(constructor))
}
icondb_error := &null
result := db.c_interface(query)
case type(result) of {
"integer" | "null" : return result
"list" : case type(result[1]) of {
"list":
if /constructor then
suspend !result
else {
if result[1] & *constructor() ~= *result[1] then
stop("dbquery: ",image(constructor)," needs at least ",*rec[1]," fields." )
suspend constructor!!result
}
"integer" : icondb_error := result
}
}
end
|