3 * Copyright (C)2007-2008 Versabanq Innovations Inc. and contributors.
4 * See the included file named LICENSE for license information.
8 using System
.Data
.Common
;
9 using System
.Data
.Odbc
;
10 using System
.Data
.SqlTypes
;
11 using System
.Data
.SqlClient
;
12 using System
.Collections
.Generic
;
20 public abstract class WvDbi
: IDisposable
22 static WvIni settings
= new WvIni("wvodbc.ini");
23 protected static WvLog log
= new WvLog("WvDbi", WvLog
.L
.Debug1
);
25 // MSSQL freaks out if there are more than 100 connections open at a
26 // time. Give ourselves a safety margin.
27 static int num_active
= 0;
28 static int max_active
= 50;
30 public static WvDbi
create(string moniker
)
32 log
.print("Creating '{0}'\n", moniker
);
34 if (!moniker
.Contains(":") && settings
[moniker
].Count
> 0)
36 var sect
= settings
[moniker
];
38 if (sect
["driver"] == "SqlClient")
39 return create(wv
.fmt("mssql:"
40 + "server={0};database={1};"
41 + "User ID={2};Password={3};",
44 sect
["user"], sect
["password"]));
46 return create(wv
.fmt("ado:"
47 + "driver={0};server={1};database={2};"
49 sect
["driver"], sect
["server"],
51 sect
["user"], sect
["password"]));
54 if (moniker
.StartsWith("dsn=") || moniker
.StartsWith("driver="))
55 return create("ado:" + moniker
);
57 WvDbi dbi
= WvMoniker
<WvDbi
>.create(moniker
);
60 (wv
.fmt("No moniker found for '{0}'", moniker
));
66 wv
.assert(num_active
< max_active
,
67 "BUG: Too many open WvDbi connections");
73 wv
.assert(false, "A WvDbi object was not Dispose()d");
76 // Implement IDisposable.
77 public virtual void Dispose()
80 GC
.SuppressFinalize(this);
83 public abstract WvSqlRows
select(string sql
, params object[] args
);
84 public abstract int execute(string sql
, params object[] args
);
86 public WvSqlRow
select_onerow(string sql
, params object[] args
)
88 // only iterates a single row, if it exists
89 foreach (WvSqlRow r
in select(sql
, args
))
90 return r
; // only return the first one
94 public WvAutoCast
select_one(string sql
, params object[] args
)
96 var a
= select_onerow(sql
, args
);
97 if (a
!= null && a
.Length
> 0)
100 return WvAutoCast
._null
;
103 public int exec(string sql
, params object[] args
)
105 return execute(sql
, args
);
108 public int try_execute(string sql
, params object[] args
)
112 return execute(sql
, args
);
116 // well, I guess no rows were affected...
121 public int try_exec(string sql
, params object[] args
)
123 return try_execute(sql
, args
);
127 public class WvDbi_IDbConnection
: WvDbi
130 protected IDbConnection db
131 { get { return _db; }
}
133 public WvDbi_IDbConnection()
137 public override void Dispose()
145 protected void opendb(IDbConnection db
)
148 if ((db
.State
& System
.Data
.ConnectionState
.Open
) == 0)
152 public override WvSqlRows
select(string sql
, params object[] args
)
154 return new WvSqlRows_IDataReader(prepare(sql
, args
));
157 public override int execute(string sql
, params object[] args
)
159 return prepare(sql
, args
).ExecuteNonQuery();
162 protected virtual IDbCommand
prepare(string sql
, params object[] args
)
164 IDbCommand cmd
= db
.CreateCommand();
165 cmd
.CommandText
= sql
;
167 for (int i
= 0; i
< args
.Length
; i
++)
170 IDbDataParameter param
;
171 if (cmd
.Parameters
.Count
<= i
)
172 cmd
.Parameters
.Add(param
= cmd
.CreateParameter());
174 param
= (IDbDataParameter
)cmd
.Parameters
[i
];
177 param
.DbType
= DbType
.DateTime
;
182 param
.DbType
= DbType
.Int32
;
187 string s
= a
.ToString();
188 param
.DbType
= DbType
.String
; // I sure hope so...
190 param
.Size
= s
.Length
;
199 public class WvDbi_ODBC
: WvDbi_IDbConnection
201 public static void wvmoniker_register()
203 WvMoniker
<WvDbi
>.register("ado",
204 (string m
, object o
) => new WvDbi_ODBC(m
));
205 WvMoniker
<WvDbi
>.register("odbc",
206 (string m
, object o
) => new WvDbi_ODBC(m
));
207 WvMoniker
<WvDbi
>.register("mysql",
208 (string m
, object o
) => new WvDbi_ODBC("MySQL:" + m
));
211 public WvDbi_ODBC(string moniker
)
214 if (moniker
.StartsWith("dsn=") || moniker
.StartsWith("driver="))
218 // try to parse it as an URL
219 WvUrl url
= new WvUrl(moniker
);
220 if (url
.path
.StartsWith("/"))
221 url
.path
= url
.path
.Substring(1);
222 if (url
.method
== "file") // method not provided
223 real
= wv
.fmt("dsn={0};database={1};"
224 + "User ID={2};uid={2};Password={3};pwd={3}",
225 url
.host
, url
.path
, url
.user
, url
.password
);
227 real
= wv
.fmt("driver={0};server={1};database={2};"
228 + "User ID={3};uid={3};Password={4};pwd={4}",
229 url
.method
, url
.host
, url
.path
,
230 url
.user
, url
.password
);
233 log
.print("ODBC create: '{0}'\n", real
);
234 opendb(new OdbcConnection(real
));
240 public class WvDbi_MSSQL
: WvDbi_IDbConnection
242 public static void wvmoniker_register()
244 WvMoniker
<WvDbi
>.register("mssql",
245 (string m
, object o
) => new WvDbi_MSSQL(m
));
248 public WvDbi_MSSQL(string moniker
)
251 if (!moniker
.StartsWith("//"))
255 // try to parse it as an URL
256 WvUrl url
= new WvUrl(moniker
);
257 if (url
.path
.StartsWith("/"))
258 url
.path
= url
.path
.Substring(1);
259 real
= wv
.fmt("server={0};database={1};"
260 + "User ID={2};Password={3};",
261 url
.host
, url
.path
, url
.user
, url
.password
);
264 log
.print("MSSQL create: '{0}'\n", real
);
268 opendb(new SqlConnection(real
));
272 try { Dispose(); }
catch {}
277 protected override IDbCommand
prepare(string sql
, params object[] args
)
279 SqlCommand cmd
= (SqlCommand
)db
.CreateCommand();
280 cmd
.CommandText
= sql
;
282 for (int i
= 0; i
< args
.Length
; i
++)
285 if (cmd
.Parameters
.Count
<= i
)
287 string name
= wv
.fmt("@col{0}", i
);
288 cmd
.Parameters
.Add(new SqlParameter(name
, a
));
290 cmd
.Parameters
[i
].Value
= a
;