1 #region MIT license
2 //
3 // MIT license
4 //
5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 // THE SOFTWARE.
24 //
25 #endregion
26 
27 using System;
28 using System.Collections.Generic;
29 using System.Data;
30 using System.Linq;
31 using DbLinq.Schema;
32 using DbLinq.Schema.Dbml;
33 using DbLinq.Util;
34 using DbLinq.Vendor;
35 using DbLinq.Vendor.Implementation;
36 
37 namespace DbLinq.MySql
38 {
39     partial class MySqlSchemaLoader : SchemaLoader
40     {
41         private readonly IVendor vendor = new MySqlVendor();
42         public override IVendor Vendor { get { return vendor; } set { } }
43 
CreateTableName(string dbTableName, string dbSchema, INameAliases nameAliases, NameFormat nameFormat)44         protected override TableName CreateTableName(string dbTableName, string dbSchema, INameAliases nameAliases, NameFormat nameFormat)
45         {
46             return CreateTableName(dbTableName, dbSchema, nameAliases, nameFormat, WordsExtraction.FromDictionary);
47         }
48 
LoadStoredProcedures(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat)49         protected override void LoadStoredProcedures(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat)
50         {
51             var procs = ReadProcedures(conn, schemaName.DbName);
52 
53             foreach (DataStoredProcedure proc in procs)
54             {
55                 var procedureName = CreateProcedureName(proc.specific_name, proc.db, nameFormat);
56 
57                 var func = new Function();
58                 func.Name = procedureName.DbName;
59                 func.Method = procedureName.MethodName;
60                 func.IsComposable = string.Compare(proc.type, "FUNCTION") == 0;
61                 func.BodyContainsSelectStatement = proc.body != null
62                                                    && proc.body.IndexOf("select", StringComparison.OrdinalIgnoreCase) > -1;
63                 ParseProcParams(proc, func);
64 
65                 schema.Functions.Add(func);
66             }
67         }
68 
LoadConstraints(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat, Names names)69         protected override void LoadConstraints(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat, Names names)
70         {
71             var constraints = ReadConstraints(conn, schemaName.DbName);
72 
73             //sort tables - parents first (this is moving to SchemaPostprocess)
74             //TableSorter.Sort(tables, constraints);
75 
76             foreach (DataConstraint keyColRow in constraints)
77             {
78                 //find my table:
79                 string fullKeyDbName = GetFullDbName(keyColRow.TableName, keyColRow.TableSchema);
80                 DbLinq.Schema.Dbml.Table table = schema.Tables.FirstOrDefault(t => fullKeyDbName == t.Name);
81                 if (table == null)
82                 {
83                     bool ignoreCase = true;
84                     table = schema.Tables.FirstOrDefault(t => 0 == string.Compare(fullKeyDbName, t.Name, ignoreCase));
85                     if (table == null)
86                     {
87                         WriteErrorLine("ERROR L46: Table '" + keyColRow.TableName + "' not found for column " + keyColRow.ColumnName);
88                         continue;
89                     }
90                 }
91 
92                 bool isForeignKey = keyColRow.ConstraintName != "PRIMARY"
93                                     && keyColRow.ReferencedTableName != null;
94 
95                 if (isForeignKey)
96                 {
97                     LoadForeignKey(schema, table, keyColRow.ColumnName, keyColRow.TableName, keyColRow.TableSchema,
98                                    keyColRow.ReferencedColumnName, keyColRow.ReferencedTableName, keyColRow.ReferencedTableSchema,
99                                    keyColRow.ConstraintName, nameFormat, names);
100                 }
101 
102             }
103         }
104 
ParseProcParams(DataStoredProcedure inputData, Function outputFunc)105         protected void ParseProcParams(DataStoredProcedure inputData, Function outputFunc)
106         {
107             string paramString = inputData.param_list;
108             if (string.IsNullOrEmpty(paramString))
109             {
110                 //nothing to parse
111             }
112             else
113             {
114                 string[] parts = paramString.Split(',');
115 
116                 foreach (string part in parts) //part='OUT param1 int'
117                 {
118                     DbLinq.Schema.Dbml.Parameter paramObj = ParseParameterString(part);
119                     if (paramObj != null)
120                         outputFunc.Parameters.Add(paramObj);
121                 }
122             }
123 
124             if (!string.IsNullOrEmpty(inputData.returns))
125             {
126                 var paramRet = new Return();
127                 paramRet.DbType = inputData.returns;
128                 paramRet.Type = ParseDbType(null, inputData.returns);
129                 outputFunc.Return = paramRet;
130             }
131         }
132 
133         /// <summary>
134         /// parse strings such as 'INOUT param2 INT' or 'param4 varchar ( 32 )'
135         /// </summary>
136         /// <param name="paramStr"></param>
137         /// <returns></returns>
ParseParameterString(string param)138         protected DbLinq.Schema.Dbml.Parameter ParseParameterString(string param)
139         {
140             param = param.Trim();
141             var inOut = DbLinq.Schema.Dbml.ParameterDirection.In;
142 
143             if (param.StartsWith("IN", StringComparison.CurrentCultureIgnoreCase))
144             {
145                 inOut = DbLinq.Schema.Dbml.ParameterDirection.In;
146                 param = param.Substring(2).Trim();
147             }
148             if (param.StartsWith("INOUT", StringComparison.CurrentCultureIgnoreCase))
149             {
150                 inOut = DbLinq.Schema.Dbml.ParameterDirection.InOut;
151                 param = param.Substring(5).Trim();
152             }
153             if (param.StartsWith("OUT", StringComparison.CurrentCultureIgnoreCase))
154             {
155                 inOut = DbLinq.Schema.Dbml.ParameterDirection.Out;
156                 param = param.Substring(3).Trim();
157             }
158 
159             int indxSpace = param.IndexOfAny(new char[] { ' ', '\t' });
160             if (indxSpace == -1)
161                 return null; //cannot find space between varName and varType
162 
163             string varName = param.Substring(0, indxSpace);
164             string varType = param.Substring(indxSpace + 1);
165 
166             var paramObj = new Parameter();
167             paramObj.Direction = inOut;
168             paramObj.Name = varName;
169             paramObj.DbType = varType;
170             paramObj.Type = ParseDbType(varName, varType);
171 
172             return paramObj;
173         }
174 
175         static System.Text.RegularExpressions.Regex re_CHARSET = new System.Text.RegularExpressions.Regex(@" CHARSET \w+$");
176         /// <summary>
177         /// given 'CHAR(30)', return 'string'
178         /// </summary>
ParseDbType(string columnName, string dbType1)179         protected string ParseDbType(string columnName, string dbType1)
180         {
181             //strip 'CHARSET latin1' from the end
182             string dbType2 = re_CHARSET.Replace(dbType1, "");
183             var dataType = new DataType();
184             dataType.UnpackRawDbType(dbType2);
185             return MapDbType(columnName, dataType).ToString();
186         }
187     }
188 }
189