New tests.
[mono.git] / mcs / class / System.Data.Linq / src / DbLinq.Sqlite / SqliteSchemaLoader.cs
1 #region MIT license\r
2 // \r
3 // MIT license\r
4 //\r
5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne\r
6 // \r
7 // Permission is hereby granted, free of charge, to any person obtaining a copy\r
8 // of this software and associated documentation files (the "Software"), to deal\r
9 // in the Software without restriction, including without limitation the rights\r
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
11 // copies of the Software, and to permit persons to whom the Software is\r
12 // furnished to do so, subject to the following conditions:\r
13 // \r
14 // The above copyright notice and this permission notice shall be included in\r
15 // all copies or substantial portions of the Software.\r
16 // \r
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
23 // THE SOFTWARE.\r
24 // \r
25 #endregion\r
26 using System;\r
27 using System.Collections.Generic;\r
28 using System.Data;\r
29 using System.IO;\r
30 using System.Linq;\r
31 using DbLinq.Schema;\r
32 using DbLinq.Schema.Dbml;\r
33 using DbLinq.Sqlite;\r
34 using DbLinq.Sqlite.Schema;\r
35 using DbLinq.Util;\r
36 using DbLinq.Vendor;\r
37 using DbLinq.Vendor.Implementation;\r
38 \r
39 namespace DbLinq.Sqlite\r
40 {\r
41     partial class SqliteSchemaLoader : SchemaLoader\r
42     {\r
43         private readonly IVendor vendor = new SqliteVendor();\r
44         public override IVendor Vendor { get { return vendor; } set { } }\r
45 \r
46         protected string UnquoteSqlName(string name)\r
47         {\r
48             var quotes = new[]{\r
49                 new { Start = "[",  End = "]" },\r
50                 new { Start = "`",  End = "`" },\r
51                 new { Start = "\"", End = "\"" },\r
52             };\r
53             foreach (var q in quotes)\r
54             {\r
55                 if (name.StartsWith(q.Start) && name.EndsWith(q.End))\r
56                     return name.Substring(q.Start.Length, name.Length - q.Start.Length - q.End.Length);\r
57             }\r
58             return name;\r
59         }\r
60 \r
61         // note: the ReadDataNameAndSchema relies on information order;\r
62         // tbl_name MUST be first\r
63         const string SelectTablesFormat = \r
64 @"   SELECT tbl_name{0}\r
65        FROM sqlite_master\r
66       WHERE type='table' AND\r
67             tbl_name NOT LIKE 'sqlite_%'\r
68    ORDER BY tbl_name";\r
69 \r
70 \r
71         /// <summary>\r
72         /// Gets a usable name for the database.\r
73         /// </summary>\r
74         /// <param name="databaseName">Name of the database.</param>\r
75         /// <returns></returns>\r
76         protected override string GetDatabaseName(string databaseName)\r
77         {\r
78             return Path.GetFileNameWithoutExtension(databaseName);\r
79         }\r
80 \r
81         protected override void LoadConstraints(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat, Names names)\r
82         {\r
83             var constraints = ReadConstraints(conn, schemaName.DbName);\r
84 \r
85             //sort tables - parents first (this is moving to SchemaPostprocess)\r
86             //TableSorter.Sort(tables, constraints); \r
87 \r
88             // Deal with non existing foreign key database\r
89             if (constraints != null)\r
90             {\r
91                 foreach (DataConstraint keyColRow in constraints)\r
92                 {\r
93                     //find my table:\r
94                     string tableFullDbName = GetFullDbName(keyColRow.TableName, keyColRow.TableSchema);\r
95                     DbLinq.Schema.Dbml.Table table = schema.Tables.FirstOrDefault(t => tableFullDbName == t.Name);\r
96                     if (table == null)\r
97                     {\r
98                         WriteErrorLine("ERROR L46: Table '" + keyColRow.TableName + "' not found for column " + keyColRow.ColumnName);\r
99                         continue;\r
100                     }\r
101 \r
102                     bool isForeignKey = keyColRow.ConstraintName != "PRIMARY"\r
103                                         && keyColRow.ReferencedTableName != null;\r
104 \r
105                     if (isForeignKey)\r
106                     {\r
107                         LoadForeignKey(schema, table, keyColRow.ColumnName, keyColRow.TableName, keyColRow.TableSchema,\r
108                                        keyColRow.ReferencedColumnName, keyColRow.ReferencedTableName,\r
109                                        keyColRow.ReferencedTableSchema,\r
110                                        keyColRow.ConstraintName, nameFormat, names);\r
111 \r
112                     }\r
113 \r
114                 }\r
115             }\r
116         }\r
117 \r
118         /// <summary>\r
119         /// parse strings such as 'INOUT param2 INT' or 'param4 varchar ( 32 )'\r
120         /// </summary>\r
121         /// <param name="param"></param>\r
122         /// <returns></returns>\r
123         protected DbLinq.Schema.Dbml.Parameter ParseParameterString(string param)\r
124         {\r
125             param = param.Trim();\r
126             var inOut = DbLinq.Schema.Dbml.ParameterDirection.In;\r
127 \r
128             if (param.StartsWith("IN", StringComparison.CurrentCultureIgnoreCase))\r
129             {\r
130                 inOut = DbLinq.Schema.Dbml.ParameterDirection.In;\r
131                 param = param.Substring(2).Trim();\r
132             }\r
133             if (param.StartsWith("INOUT", StringComparison.CurrentCultureIgnoreCase))\r
134             {\r
135                 inOut = DbLinq.Schema.Dbml.ParameterDirection.InOut;\r
136                 param = param.Substring(5).Trim();\r
137             }\r
138             if (param.StartsWith("OUT", StringComparison.CurrentCultureIgnoreCase))\r
139             {\r
140                 inOut = DbLinq.Schema.Dbml.ParameterDirection.Out;\r
141                 param = param.Substring(3).Trim();\r
142             }\r
143 \r
144             int indxSpace = param.IndexOfAny(new char[] { ' ', '\t' });\r
145             if (indxSpace == -1)\r
146                 return null; //cannot find space between varName and varType\r
147 \r
148             string varName = param.Substring(0, indxSpace);\r
149             string varType = param.Substring(indxSpace + 1);\r
150 \r
151             DbLinq.Schema.Dbml.Parameter paramObj = new DbLinq.Schema.Dbml.Parameter();\r
152             paramObj.Direction = inOut;\r
153             paramObj.Name = varName;\r
154             paramObj.DbType = varType;\r
155             paramObj.Type = ParseDbType(varType);\r
156 \r
157             return paramObj;\r
158         }\r
159 \r
160         static System.Text.RegularExpressions.Regex re_CHARSET = new System.Text.RegularExpressions.Regex(@" CHARSET \w+$");\r
161         /// <summary>\r
162         /// given 'CHAR(30)', return 'string'\r
163         /// </summary>\r
164         protected string ParseDbType(string dbType1)\r
165         {\r
166             //strip 'CHARSET latin1' from the end\r
167             string dbType2 = re_CHARSET.Replace(dbType1, "");\r
168 \r
169             var dataType = new DataType();\r
170             dataType.UnpackRawDbType(dbType2);\r
171             return MapDbType(null, dataType).ToString();\r
172         }\r
173     }\r
174 }\r