Skip to content

Commit a790145

Browse files
committed
Changes relating to post 9
1 parent dfcc022 commit a790145

20 files changed

+715
-190
lines changed

MySQLTestHarness/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ private static void RunQueries(object StateInfo)
2828
{
2929
using (var conn = new MySql.Data.MySqlClient.MySqlConnection(@"Server=localhost;Database=employees;Uid=root"))
3030
//using (var comm = new MySql.Data.MySqlClient.MySqlCommand(@"SELECT (emp_no * 3.14) + 10, emp_no, first_name, last_name FROM employees", conn))
31-
using (var comm = new MySql.Data.MySqlClient.MySqlCommand(@"SELECT MYSQLDOTNET_INT('MySQLCustomClass.CustomMySQLClass', emp_no), emp_no, first_name, last_name FROM employees", conn))
31+
using (var comm = new MySql.Data.MySqlClient.MySqlCommand(@"SELECT CAST(mysqldotnet_string(""MySQLCustomClass.CustomMySQLClass"", ""MULTI"", first_name, first_name, first_name) AS char) FROM employees.employees", conn))
3232
using (var dt = new System.Data.DataTable())
3333
{
3434
comm.CommandTimeout = 600;

MySQLUDFInstaller x64/Product.wxs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
3-
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension">
3+
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension" >
44

55
<Product Id="*" Name="MySQL .NET UDF" Language="1033" Version="1.0.0.0" Manufacturer="James Davis, www.debugthings.com"
6-
UpgradeCode="a4d9eaa0-947d-4442-a124-78a7f3ed4815" >
6+
UpgradeCode="a4d9eaa0-947d-4442-a124-78a7f3ed4815">
77
<Package InstallerVersion="405" Compressed="yes" InstallScope="perMachine"
8-
Platform="x64" Description="MySQL .NET UDF" Manufacturer="www.debugthings.com" />
8+
Platform="x64" Description="MySQL .NET UDF" Manufacturer="www.debugthings.com" />
99
<Property Id="ARPURLINFOABOUT" Value="https://github.com/jldgit/mysql_udf_dotnet" />
1010
<Property Id="ARPURLUPDATEINFO" Value="http://www.debugthings.com/mysql" />
1111
<Property Id="ARPSIZE" Value="1024" />

README.txt

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
===============================================================================
2+
MySQL .NET UDF - A UDF plugin that allows you to use .NET code to execute
3+
custom code just as you were to write a native UDF.
4+
5+
Written by James Davis.
6+
www.debugthings.com
7+
===============================================================================
8+
9+
INTRODUCTION
10+
------------
11+
While looking around at the plugins available for MySQL I noticed there wasn't
12+
much in the way of things for Windows. Even more scare were any items relating
13+
to .NET.
14+
15+
I wrote a wrapper around the .NET Hosting APIs to allow a developer to code in
16+
.NET and avoid all of the issues surrounding memory management, threading, and
17+
isolation of potentially harmful code.
18+
19+
You now have the power of .NET at your control and can write some very crazy
20+
albeit possibly not practical custom functions. Some examples would include
21+
using WebClient to download webpages directly into a database without having to
22+
write an application to do so.
23+
24+
QUICKSTART
25+
----------
26+
If you want to jump in using the included examples here is what you need to do.
27+
28+
* Rename mysqld.exe.config_full to mysqld.exe.config
29+
- Delete old config file
30+
* Open your favorite MySQL client and execute install_samples.sql
31+
32+
Execute one of the following stored procedures. Descriptions included.
33+
34+
simple_add3toint(int) -- Adds 3 to the input number
35+
36+
simple_add3toreal(real) -- Adds 3 to the input number
37+
38+
simple_addtostring(string) -- Adds "SIMPLE EXAMPLE" to the end of the input
39+
40+
adv_isinradius(LatCenter, LongCenter, LatPoint, LongPoint, radius) -- Calculates
41+
to see if the point is inside of the specified radius from the center.
42+
43+
adv_getwebpage(webpage) -- Uses System.WebClient to pull the raw HTML back from
44+
the URL in the function.
45+
46+
47+
WHY .NET?
48+
---------
49+
The choice for me was simple. I work in .NET all the time.
50+
51+
WHY MYSQL?
52+
----------
53+
I have always had a soft spot for MySQL. It was my first RDBMS I used to create
54+
a few websites. I started using it in 2000 and dabbled with it off and on for
55+
the past 14 years.
56+
57+
MySQL fell by the wayside once I got into a corporate environment and started
58+
using Microsoft SQL(MSSQL) and Oracle. However, one day I started thinking
59+
about ways I could use external code in MySQL similar to MSSQL.
60+
61+
The natural fit was to use .NET as that is what MSSQL used.
62+
63+
-------------------------------------------------------------------------------
64+
INSTALLATION
65+
-------------------------------------------------------------------------------
66+
This README is shown after the installation has completed. But should also be
67+
found in the "MySQL .NET UDF" installation location. Below are steps listed
68+
to do a manual installation if you happen to build your own copy or do not
69+
use the installer.
70+
71+
BASE PLUGIN INSTALL (MANUAL)
72+
----------------------------
73+
* Extract all files into a final destination folder
74+
* Install DOTNET20\MySQLHostManager.dll into the GAC
75+
- You can do this by dragging/dropping the files into %WINDIR%\assembly\
76+
or using %WINDIR%\Microsoft.NET\Framework\v2.0.50727\gacutil.exe
77+
* Install DOTNET40\MySQLHostManager.dll into the GAC
78+
- There is only one option. You can do this by using
79+
%WINDIR%\Microsoft.NET\Framework\v2.0.50727\gacutil.exe
80+
* Copy bin\mysqld.exe.config to %MYSQLHOME%\bin
81+
* Copy plugin\MySQLDotNet.dll to %MYSQLHOME%\lib\plugin
82+
* Open your favorite MySQL client and execute sql\install.sql
83+
84+
.NET CUSTOM PLUGIN INSTALL (MANUAL)
85+
-----------------------------------
86+
* Copy your custom plugin dll to %MYSQLHOME%\lib\plugin
87+
- Optionally you may copy it to %MYSQLHOME%\lib\plugin\<DLLNAME>
88+
- See section on custom assemblies
89+
* Edit %MYSQLHOME%\bin\mysqld.exe.config to include your assembly
90+
- Examples are inside of the config file
91+
92+
93+
EXECUTING CUSTOM CODE (MINI VERSION)
94+
------------------------------------
95+
If the install went well
96+
97+
-------------------------------------------------------------------------------
98+
HOW TO USE
99+
-------------------------------------------------------------------------------
100+
Once both the base plugin and your custom plugin are installed you need to tell
101+
MySQL what assemblies it is allowed to load. To do this you need to edit the
102+
.config file to include a new config section. Once the config section is added
103+
you need to tell the application the name of your assembly to load.
104+
105+
This assembly will get picked up from the GAC or from lib\plugin or
106+
lib\plugin\ASSEMBLYNAME.
107+
108+
CUSTOM SECTION DECLARATION
109+
--------------------------
110+
<configSections>
111+
<section name ="mysqlassemblies" type="MySQLHostManager.MySQLAssemblyList,
112+
MySQLHostManager, Version=2.0.0.0, Culture=neutral,
113+
PublicKeyToken=71c4a5d4270bd29c"/>
114+
</configSections>
115+
116+
This is a standard custom section declaration. You can find out more
117+
information from MSDN.
118+
119+
ASSEMBLY CONFIG DEFINITIION
120+
---------------------------
121+
<mysqlassemblies>
122+
<assemblies>
123+
<assembly name="MySQLCustomClass.CustomMySQLClass"
124+
fullname ="MySQLCustomClass,
125+
Version=1.0.0.0, PublicKeyToken=a55d172c54d273f4"
126+
clrversion="4.0" lifetime="02:00:00"/>
127+
</assemblies>
128+
</mysqlassemblies>
129+
130+
This is a custom section that defines the assembly to be loaded. You must
131+
sign your assembly and use a (partial) strong name. This is a safety feature
132+
and protects against rogue code.
133+
134+
ATTRIBUTES
135+
----------
136+
- name: The fully qualified name of the class that you wish to use
137+
- fullname: The strong name of your assembly
138+
- clrversion: The required version of the CLR. Uses default if not specified
139+
- lifetime: How long the appdomains live for this assembly
140+
141+
APPDOMAIN CONFIG DEFINITIION
142+
----------------------------
143+
<mysqlassemblies>
144+
<appDomainCleanup
145+
interval="0.00:05:00"
146+
forcedInterval="1.00:00:00" />
147+
</mysqlassemblies>
148+
149+
All of the domains are entered into a pool and reused. After the specified
150+
lifetime the domains are released from the pool and set to "die." This custom
151+
section controls intervals the removed domains are unloaded from the
152+
application.
153+
154+
The only time domains are checked for life is when they are being pulled from
155+
the pool and being released from active use. The forcedInterval makes sure that
156+
upon the next unload check the system will iterate through all appdomains and
157+
force the timeout check.
158+
159+
ATTRIBUTES
160+
----------
161+
- interval: The timespan between checking to unload.
162+
- forcedInterval: All domains are scanned and cleared if they meet the criteria
163+
164+
PERMISSION SET CONFIG DEFINITION
165+
--------------------------------
166+
<mysqlassemblies>
167+
<permissionsets>
168+
<permissionset name="MySQLPartial">
169+
<permissions>
170+
<add name="FileIOPermission" />
171+
</permissions>
172+
</permissionset>
173+
<!---->
174+
</permissionsets>
175+
<mysqlassemblies>
176+
177+
In order to secure the host and to secure the code the AppDomain manager
178+
enforces Code Access Security. In order to run specific methods inside of
179+
MySQL we need to grant specific code access.
180+
181+
These names come from the standard code access security classes inside of
182+
.NET. Check MSDN for a description of each class. Some common permissions:
183+
184+
- FileIOPermission
185+
- WebPermission
186+
- RegistryPermission
187+
- EventLogPermission
188+

clr_host/ClrHost.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ CClrHost::CClrHost() : m_started(false), m_pClrControl(NULL)
3939
/// </summary>
4040
CClrHost::~CClrHost()
4141
{
42+
43+
4244
//// free the AppDomainManagers
4345
//for (AppDomainManagerMap::iterator iAdm = m_appDomainManagers.begin(); iAdm != m_appDomainManagers.end(); iAdm++)
4446
// iAdm->second->Release();

mysql_managed_interface/IManagedHost.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ public interface IManagedHost
3333
double RunReal(string functionName, double value);
3434
double RunReals(string functionName, double[] values);
3535

36-
36+
[return: MarshalAs(UnmanagedType.BStr)]
3737
string RunString(string functionName, string value);
38+
[return: MarshalAs(UnmanagedType.BStr)]
3839
string RunStrings(string functionName, string[] values);
3940

4041
[return: MarshalAs(UnmanagedType.BStr)]
@@ -45,6 +46,9 @@ public interface IManagedHost
4546
string GetAppDomainName { get; }
4647

4748
bool Unload(string FriendlyName);
49+
50+
string MultiKeyword { get; }
51+
int DefaultCodepage { get; }
4852
}
4953

5054
}

mysql_managed_interface/MySQLAssemblyList.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ public MySQLAppDomainCleanup appDomainCleanup
4040
return (MySQLAppDomainCleanup)base["appDomainCleanup"];
4141
}
4242
}
43+
44+
[ConfigurationProperty("applicationDefaults")]
45+
public MySQLDefaultSettings applicationDefaults
46+
{
47+
get
48+
{
49+
return (MySQLDefaultSettings)base["applicationDefaults"];
50+
}
51+
}
4352
}
4453

4554
public class MySQLAssemblies : ConfigurationElementCollection
@@ -291,4 +300,34 @@ public int maxAllowableDomains
291300
}
292301

293302
}
303+
304+
public class MySQLDefaultSettings : ConfigurationElement
305+
{
306+
[ConfigurationProperty("codepage", DefaultValue = 1252)]
307+
public int codepage
308+
{
309+
get
310+
{
311+
return (int)this["codepage"];
312+
}
313+
set
314+
{
315+
this["codepage"] = value;
316+
}
317+
}
318+
319+
[ConfigurationProperty("multikeyword", DefaultValue = "MULTI")]
320+
public string multikeyword
321+
{
322+
get
323+
{
324+
return (string)this["multikeyword"];
325+
}
326+
set
327+
{
328+
this["multikeyword"] = value;
329+
}
330+
}
331+
332+
}
294333
}

mysql_managed_interface/MySQLHostManager.cs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,19 @@ private PermissionSet GetAssemblyPermissions(MySQLAsembly typeName)
258258
{
259259
PermissionSet permissions = new PermissionSet(PermissionState.None);
260260
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
261-
262-
if (!string.IsNullOrEmpty(typeName.permissions))
261+
string permissionSetName = string.Empty;
262+
if (string.IsNullOrEmpty(typeName.permissions))
263+
{
264+
permissionSetName = "MySQLPartial";
265+
}
266+
else
267+
{
268+
permissionSetName = typeName.permissions;
269+
}
270+
if (!string.IsNullOrEmpty(permissionSetName))
263271
{
264-
if (typeName.permissions.Equals("fulltrust", StringComparison.InvariantCultureIgnoreCase))
272+
273+
if (permissionSetName.Equals("fulltrust", StringComparison.InvariantCultureIgnoreCase))
265274
{
266275
// override the default permission set with a full trust permission set.
267276
permissions = new PermissionSet(PermissionState.Unrestricted);
@@ -270,7 +279,7 @@ private PermissionSet GetAssemblyPermissions(MySQLAsembly typeName)
270279
{
271280
var section2 = System.Configuration.ConfigurationManager.GetSection("mysqlassemblies") as MySQLAssemblyList;
272281
var permlists = section2.permissionsetscollection;
273-
var permlist = permlists[typeName.permissions];
282+
var permlist = permlists[permissionSetName];
274283

275284
// For now we're adding all of the permissions out of the box for System, System.Configuration, System.Data. and System.Xml
276285
// This is heavy handed, but aides in beta testing. By the end we should have pared this down to a handful of useful permissions
@@ -279,6 +288,7 @@ private PermissionSet GetAssemblyPermissions(MySQLAsembly typeName)
279288
{
280289
switch (permission.Name)
281290
{
291+
282292
case "AspNetHostingPermission": permissions.AddPermission(new System.Web.AspNetHostingPermission(PermissionState.Unrestricted)); break;
283293
//case "Collaboration": permissions.AddPermission(new System.Net.PeerToPeer.Collaboration.PeerCollaborationPermission(PermissionState.Unrestricted));
284294
// break;
@@ -431,7 +441,7 @@ public IManagedHost CreateAppDomain(string typeName)
431441
if (activeAppDomains != null && activeAppDomains.Count > 0)
432442
{
433443
IManagedHost toReturn = null;
434-
if (System.Threading.Monitor.TryEnter(objLock,10)) // Large lock space to make sure we don't read from the collection while it's being written to.
444+
if (System.Threading.Monitor.TryEnter(objLock, 10)) // Large lock space to make sure we don't read from the collection while it's being written to.
435445
{
436446
try
437447
{
@@ -676,7 +686,6 @@ public double RunReals(string functionName, double[] values)
676686
InitFunctions(functionName);
677687
return functions[functionName].RunReals(values);
678688
}
679-
680689
public string RunString(string functionName, string value)
681690
{
682691
InitFunctions(functionName);
@@ -690,5 +699,28 @@ public string RunStrings(string functionName, string[] values)
690699
}
691700

692701
#endregion
702+
703+
704+
705+
706+
public string MultiKeyword
707+
{
708+
get
709+
{
710+
var section2 = System.Configuration.ConfigurationManager.GetSection("mysqlassemblies") as MySQLAssemblyList;
711+
var permlists = section2.applicationDefaults;
712+
return permlists.multikeyword;
713+
}
714+
}
715+
716+
public int DefaultCodepage
717+
{
718+
get
719+
{
720+
var section2 = System.Configuration.ConfigurationManager.GetSection("mysqlassemblies") as MySQLAssemblyList;
721+
var permlists = section2.applicationDefaults;
722+
return permlists.codepage;
723+
}
724+
}
693725
}
694726
}

mysql_managed_interface/MySQLHostManager20.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,12 @@
9393
</ItemGroup>
9494
<ItemGroup>
9595
<None Include="generic_signing.snk" />
96+
<None Include="mysqld.exe.config_full">
97+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
98+
</None>
9699
<None Include="mysqld.exe.config">
97100
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
101+
<SubType>Designer</SubType>
98102
</None>
99103
</ItemGroup>
100104
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

0 commit comments

Comments
 (0)