├── .gitattributes ├── .gitignore ├── Checks ├── App.config ├── Checks.csproj ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── InstallerScriptGenerator ├── App.config ├── BO │ ├── InstallerScriptableClrMethod.cs │ ├── InstallerScriptableItem.cs │ ├── InstallerScriptableSqlAssembly.cs │ ├── InstallerScriptableSqlFunction.cs │ ├── InstallerScriptableSqlProcedure.cs │ └── SqlParameter.cs ├── InstallerScriptGenerator.csproj ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── TemplateParser.cs └── Utils │ └── ClrSqlTermsConverter.cs ├── README.md ├── RediSQLCache.sln ├── RedisSqlCache ├── Common │ └── DateTimeUtils.cs ├── Deployment │ ├── BasicUsageSamples.sql │ ├── Install.Sql │ ├── LICENSE.txt │ ├── Readme.txt │ └── Uninstall.sql ├── Properties │ └── AssemblyInfo.cs ├── RediSql.csproj ├── RedisSharp │ └── RedisSharp.cs ├── Scripts │ ├── DeploymentScriptsGenerator.ps1 │ ├── InstallerTemplate.txt │ ├── SanityTest.sql │ ├── UninstallTemplate.txt │ └── Usage.sql ├── SqlClrComponents │ ├── Common │ │ └── RedisConnection.cs │ ├── Enums.cs │ ├── RedisqlGlobalServerFunctions.cs │ ├── RedisqlKeysManipulationFunctions.cs │ ├── RedisqlLists.cs │ ├── RedisqlRowsets.cs │ └── RedisqlStringValuesFunctions.cs └── TSQLCode │ ├── GetSetStoredRowset.sql │ ├── GetStoredRowset.sql │ └── XmlToRowset.sql ├── ScriptGenerator ├── InstallerScriptGenerator.exe ├── InstallerScriptGenerator.exe.config ├── InstallerScriptGenerator.vshost.exe ├── InstallerScriptGenerator.vshost.exe.config ├── InstallerScriptGenerator.vshost.exe.manifest └── SqlClrDeclarations.dll └── SqlClrDeclarations ├── Attributes ├── ExportedFunctionAttribute.cs ├── SqlInstallerScriptGeneratorExportedAttributeBase.cs ├── SqlInstallerScriptGeneratorExportedProcedure.cs └── SqlParameterAttribute.cs ├── Properties └── AssemblyInfo.cs └── SqlClrDeclarations.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | *.vspx 85 | 86 | # TFS 2012 Local Workspace 87 | $tf/ 88 | 89 | # Guidance Automation Toolkit 90 | *.gpState 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper*/ 94 | *.[Rr]e[Ss]harper 95 | *.DotSettings.user 96 | 97 | # JustCode is a .NET coding add-in 98 | .JustCode 99 | 100 | # TeamCity is a build add-in 101 | _TeamCity* 102 | 103 | # DotCover is a Code Coverage Tool 104 | *.dotCover 105 | 106 | # NCrunch 107 | _NCrunch_* 108 | .*crunch*.local.xml 109 | 110 | # MightyMoose 111 | *.mm.* 112 | AutoTest.Net/ 113 | 114 | # Web workbench (sass) 115 | .sass-cache/ 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | 133 | # Publish Web Output 134 | *.[Pp]ublish.xml 135 | *.azurePubxml 136 | ## TODO: Comment the next line if you want to checkin your 137 | ## web deploy settings but do note that will include unencrypted 138 | ## passwords 139 | #*.pubxml 140 | 141 | *.publishproj 142 | 143 | # NuGet Packages 144 | *.nupkg 145 | # The packages folder can be ignored because of Package Restore 146 | **/packages/* 147 | # except build/, which is used as an MSBuild target. 148 | !**/packages/build/ 149 | # Uncomment if necessary however generally it will be regenerated when needed 150 | #!**/packages/repositories.config 151 | 152 | # Windows Azure Build Output 153 | csx/ 154 | *.build.csdef 155 | 156 | # Windows Store app package directory 157 | AppPackages/ 158 | 159 | # Visual Studio cache files 160 | # files ending in .cache can be ignored 161 | *.[Cc]ache 162 | # but keep track of directories ending in .cache 163 | !*.[Cc]ache/ 164 | 165 | # Others 166 | ClientBin/ 167 | [Ss]tyle[Cc]op.* 168 | ~$* 169 | *~ 170 | *.dbmdl 171 | *.dbproj.schemaview 172 | *.pfx 173 | *.publishsettings 174 | node_modules/ 175 | orleans.codegen.cs 176 | 177 | # RIA/Silverlight projects 178 | Generated_Code/ 179 | 180 | # Backup & report files from converting an old project file 181 | # to a newer Visual Studio version. Backup files are not needed, 182 | # because we have git ;-) 183 | _UpgradeReport_Files/ 184 | Backup*/ 185 | UpgradeLog*.XML 186 | UpgradeLog*.htm 187 | 188 | # SQL Server files 189 | *.mdf 190 | *.ldf 191 | 192 | # Business Intelligence projects 193 | *.rdl.data 194 | *.bim.layout 195 | *.bim_*.settings 196 | 197 | # Microsoft Fakes 198 | FakesAssemblies/ 199 | 200 | # Node.js Tools for Visual Studio 201 | .ntvs_analysis.dat 202 | 203 | # Visual Studio 6 build log 204 | *.plg 205 | 206 | # Visual Studio 6 workspace options file 207 | *.opt 208 | 209 | # LightSwitch generated files 210 | GeneratedArtifacts/ 211 | _Pvt_Extensions/ 212 | ModelManifest.xml 213 | -------------------------------------------------------------------------------- /Checks/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Checks/Checks.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A726DF9E-E4F2-470E-8E4D-B8A760D80653} 8 | Exe 9 | Properties 10 | Checks 11 | Checks 12 | v4.6 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | {666fe4b7-0a6b-44df-b179-c394234e33de} 55 | RediSql 56 | 57 | 58 | 59 | 66 | -------------------------------------------------------------------------------- /Checks/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using RediSql.SqlClrComponents; 7 | 8 | namespace Checks 9 | { 10 | class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | var a = RedisqlLists.GetListItems("localhost", 6379, null, null, "Sdgsdg", 0 , -1); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Checks/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Checks")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Checks")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a726df9e-e4f2-470e-8e4d-b8a760d80653")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/BO/InstallerScriptableClrMethod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace InstallerScriptGenerator.BO 9 | { 10 | internal abstract class InstallerScriptableClrMethod : InstallerScriptableItem 11 | { 12 | protected Type ContainedType { get; set; } 13 | protected MethodInfo Method { get; set; } 14 | internal InstallerScriptableClrMethod(string name, string schemaName, InstallerScriptableSqlAssembly sqlAssembly, Type containedType, MethodInfo method) 15 | { 16 | Name = name; 17 | SchemaName = schemaName; 18 | ContainedType = containedType; 19 | Method = method; 20 | SqlAssembly = sqlAssembly; 21 | } 22 | 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/BO/InstallerScriptableItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using SqlClrDeclarations.Attributes; 8 | 9 | namespace InstallerScriptGenerator.BO 10 | { 11 | internal abstract class InstallerScriptableItem 12 | { 13 | internal string SchemaName { get; set; } 14 | internal string Name { get; set; } 15 | public InstallerScriptableSqlAssembly SqlAssembly { get; set; } 16 | 17 | internal abstract string GenerateInstallScript(); 18 | internal abstract string GenerateUninstallScript(); 19 | 20 | internal static InstallerScriptableItem GetScreiptableItem( 21 | SqlInstallerScriptGeneratorExportedAttributeBase attributeInfo, InstallerScriptableSqlAssembly sqlAssembly, 22 | MemberInfo declaredItem) 23 | { 24 | InstallerScriptableItem item = null; 25 | if (attributeInfo is SqlInstallerScriptGeneratorExportedFunction && declaredItem is MethodInfo) 26 | { 27 | item = new InstallerScriptableSqlFunction(attributeInfo.Name, attributeInfo.SchemaName, sqlAssembly, 28 | (MethodInfo)declaredItem); 29 | } 30 | if (attributeInfo is SqlInstallerScriptGeneratorExportedProcedure && declaredItem is MethodInfo) 31 | { 32 | item = new InstallerScriptableSqlProcedure(attributeInfo.Name, attributeInfo.SchemaName, sqlAssembly, 33 | (MethodInfo)declaredItem); 34 | } 35 | if (item == null) 36 | throw new ArgumentOutOfRangeException(nameof(attributeInfo), "unexpected type of attribute"); 37 | return item; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /InstallerScriptGenerator/BO/InstallerScriptableSqlAssembly.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using SqlClrDeclarations.Attributes; 9 | 10 | namespace InstallerScriptGenerator.BO 11 | { 12 | internal class InstallerScriptableSqlAssembly : InstallerScriptableItem 13 | { 14 | internal Assembly Assembly { get; set; } 15 | internal string Path { get; set; } 16 | 17 | public InstallerScriptableSqlAssembly(Assembly assembly) 18 | { 19 | var assemblyAttribute = assembly.GetCustomAttribute(); 20 | Name = assemblyAttribute.Title; 21 | Path = assembly.Location; 22 | Assembly = assembly; 23 | } 24 | 25 | internal override string GenerateInstallScript() 26 | { 27 | string template = @" 28 | CREATE ASSEMBLY [$$$name$$$] 29 | AUTHORIZATION [dbo] 30 | FROM 0x$$$bits$$$ 31 | WITH PERMISSION_SET = UNSAFE 32 | "; 33 | return template.Replace("$$$bits$$$", BitConverter.ToString(File.ReadAllBytes(Path)).Replace("-", string.Empty)).Replace("$$$name$$$", Name); 34 | } 35 | 36 | internal override string GenerateUninstallScript() 37 | { 38 | return $"DROP ASSEMBLY [{Name}]"; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/BO/InstallerScriptableSqlFunction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Microsoft.SqlServer.Server; 8 | using SqlClrDeclarations.Attributes; 9 | 10 | namespace InstallerScriptGenerator.BO 11 | { 12 | internal class InstallerScriptableSqlFunction : InstallerScriptableClrMethod 13 | { 14 | private readonly SqlInstallerScriptGeneratorExportedFunction _exportedFunctionAttribute; 15 | private readonly SqlFunctionAttribute _sqlFunctionAttribute; 16 | public InstallerScriptableSqlFunction(string name, string schemaName, InstallerScriptableSqlAssembly sqlSqlAssembly, MethodInfo method) : base(name, schemaName, sqlSqlAssembly, method.DeclaringType, method) 17 | { 18 | _exportedFunctionAttribute = method.GetCustomAttribute(); 19 | _sqlFunctionAttribute = method.GetCustomAttribute(); 20 | } 21 | 22 | internal override string GenerateInstallScript() 23 | { 24 | StringBuilder sb = new StringBuilder(@" 25 | GO 26 | CREATE FUNCTION $$$SchemaName$$$.$$$SqlFunctionName$$$($$$ParametersList$$$) 27 | RETURNS $$$SqlReturnValueType$$$ 28 | AS EXTERNAL NAME[$$$SqlAssemblyName$$$].[$$$FullClrTypeName$$$].[$$$MethodName$$$] 29 | GO 30 | "); 31 | sb.Replace("$$$SchemaName$$$", SchemaName); 32 | sb.Replace("$$$SqlFunctionName$$$", Name); 33 | sb.Replace("$$$ParametersList$$$", SqlParameter.GenerateSqlParameterString(Method.GetParameters())); 34 | sb.Replace("$$$SqlReturnValueType$$$", GetSqlReturnValueType()); 35 | sb.Replace("$$$SqlAssemblyName$$$", SqlAssembly.Name); 36 | sb.Replace("$$$FullClrTypeName$$$", ContainedType.FullName); 37 | sb.Replace("$$$MethodName$$$", Method.Name); 38 | return sb.ToString(); 39 | } 40 | 41 | private string GetSqlReturnValueType() 42 | { 43 | if (!string.IsNullOrEmpty(_sqlFunctionAttribute.TableDefinition)) 44 | return $"table({_sqlFunctionAttribute.TableDefinition})"; 45 | if (!string.IsNullOrEmpty(_exportedFunctionAttribute.SqlReturnType)) 46 | return _exportedFunctionAttribute.SqlReturnType; 47 | return Utils.ClrSqlTermsConverter.ConvertClrTypeToSqlTypeName(Method.ReturnType); 48 | } 49 | 50 | 51 | 52 | internal override string GenerateUninstallScript() 53 | { 54 | return $"DROP FUNCTION {SchemaName}.{Name}"; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/BO/InstallerScriptableSqlProcedure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Microsoft.SqlServer.Server; 8 | using SqlClrDeclarations.Attributes; 9 | 10 | namespace InstallerScriptGenerator.BO 11 | { 12 | internal class InstallerScriptableSqlProcedure : InstallerScriptableClrMethod 13 | { 14 | private readonly SqlInstallerScriptGeneratorExportedProcedure _exportedProcedureAttribute; 15 | private readonly SqlProcedureAttribute _sqlProcedureAttribute; 16 | public InstallerScriptableSqlProcedure(string name, string schemaName, InstallerScriptableSqlAssembly sqlSqlAssembly, MethodInfo method) : base(name, schemaName, sqlSqlAssembly, method.DeclaringType, method) 17 | { 18 | _exportedProcedureAttribute = method.GetCustomAttribute(); 19 | _sqlProcedureAttribute = method.GetCustomAttribute(); 20 | } 21 | 22 | internal override string GenerateInstallScript() 23 | { 24 | StringBuilder sb = new StringBuilder(@" 25 | GO 26 | CREATE PROCEDURE $$$SchemaName$$$.$$$SqlProcedureName$$$($$$ParametersList$$$) 27 | AS EXTERNAL NAME[$$$SqlAssemblyName$$$].[$$$FullClrTypeName$$$].[$$$MethodName$$$] 28 | GO 29 | "); 30 | sb.Replace("$$$SchemaName$$$", SchemaName); 31 | sb.Replace("$$$SqlProcedureName$$$", Name); 32 | sb.Replace("$$$ParametersList$$$", SqlParameter.GenerateSqlParameterString(Method.GetParameters())); 33 | sb.Replace("$$$SqlAssemblyName$$$", SqlAssembly.Name); 34 | sb.Replace("$$$FullClrTypeName$$$", ContainedType.FullName); 35 | sb.Replace("$$$MethodName$$$", Method.Name); 36 | return sb.ToString(); 37 | } 38 | 39 | 40 | internal override string GenerateUninstallScript() 41 | { 42 | return $"DROP PROCEDURE {SchemaName}.{Name}"; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/BO/SqlParameter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using SqlClrDeclarations.Attributes; 8 | 9 | namespace InstallerScriptGenerator.BO 10 | { 11 | internal class SqlParameter 12 | { 13 | internal string Name { get; set; } 14 | internal object DefaultValue { get; set; } 15 | 16 | internal string SqlDefaultValue 17 | { 18 | get 19 | { 20 | if (DefaultValue == null) return null; 21 | if (DefaultValue == DBNull.Value) return "null"; 22 | if (DefaultValue == typeof(DBNull)) return "null"; 23 | if (SqlType == Utils.ClrSqlTermsConverter.ConvertClrTypeToSqlTypeName(typeof(string))) return "'" + DefaultValue + "'"; 24 | return DefaultValue.ToString(); 25 | } 26 | } 27 | internal string SqlType { get; set; } 28 | internal SqlParameter(ParameterInfo parameter) 29 | { 30 | if (parameter.IsDefined(typeof(SqlParameterAttribute))) 31 | { 32 | var attribute = (SqlParameterAttribute)parameter.GetCustomAttribute(typeof(SqlParameterAttribute)); 33 | Name = !string.IsNullOrEmpty(attribute.Name) ? attribute.Name : parameter.Name; 34 | SqlType = !string.IsNullOrEmpty(attribute.SqlType) 35 | ? attribute.SqlType 36 | : Utils.ClrSqlTermsConverter.ConvertClrTypeToSqlTypeName(parameter.ParameterType); 37 | DefaultValue = attribute.DefaultValue; 38 | if (DefaultValue is bool) 39 | DefaultValue = (bool)attribute.DefaultValue ? 0 : 1; 40 | 41 | } 42 | else 43 | { 44 | DefaultValue = null; 45 | Name = parameter.Name; 46 | SqlType = Utils.ClrSqlTermsConverter.ConvertClrTypeToSqlTypeName(parameter.ParameterType); 47 | } 48 | } 49 | 50 | internal static string GenerateSqlParameterString(ParameterInfo[] parameters) 51 | { 52 | return string.Join(", ", parameters.Select(param => 53 | { 54 | var paramInfo = new SqlParameter(param); 55 | string singleParam = $"@{paramInfo.Name} {paramInfo.SqlType}"; 56 | if (paramInfo.SqlDefaultValue != null) 57 | singleParam += $"={paramInfo.SqlDefaultValue}"; 58 | return singleParam; 59 | })); 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/InstallerScriptGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {CABBBA96-75AF-4F10-96AB-72B814B5A97E} 8 | Exe 9 | Properties 10 | InstallerScriptGenerator 11 | InstallerScriptGenerator 12 | v4.6 13 | 512 14 | true 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | false 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | ..\ScriptGenerator\ 33 | TRACE 34 | prompt 35 | 4 36 | false 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 | {56c24720-8053-4cf5-8bf8-bae7dba78424} 66 | SqlClrDeclarations 67 | 68 | 69 | 70 | 77 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using InstallerScriptGenerator.BO; 9 | using Microsoft.SqlServer.Server; 10 | using SqlClrDeclarations.Attributes; 11 | using SqlClrDeclarations.Attributes; 12 | 13 | namespace InstallerScriptGenerator 14 | { 15 | class Program 16 | { 17 | static void Main(string[] args) 18 | { 19 | string templateFile = args[0]; 20 | string outputFilePath = args[1]; 21 | TemplateParser parser = new TemplateParser(templateFile); 22 | string result = parser.ParseTemplate(); 23 | File.WriteAllText(outputFilePath, result); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("InstallerScriptGenerator")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("InstallerScriptGenerator")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("cabbba96-75af-4f10-96ab-72b814b5a97e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/TemplateParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using InstallerScriptGenerator.BO; 10 | using SqlClrDeclarations.Attributes; 11 | 12 | namespace InstallerScriptGenerator 13 | { 14 | public class TemplateParser 15 | { 16 | private FileInfo _templateFile; 17 | 18 | public TemplateParser(string filePath) 19 | { 20 | _templateFile = new FileInfo(filePath); 21 | } 22 | 23 | public string ParseTemplate() 24 | { 25 | StringBuilder sb = new StringBuilder((int)_templateFile.Length); 26 | using (var reader = _templateFile.OpenText()) 27 | { 28 | while (!reader.EndOfStream) 29 | { 30 | string line = reader.ReadLine(); 31 | if (line == null) break; 32 | var installScriptMagic = "~~~InstallScript:~~~"; 33 | var uninstallScriptMagic = "~~~UninstallScript:~~~"; 34 | var includeFileMagic = "~~~IncludeFile:~~~"; 35 | if (line.StartsWith(installScriptMagic)) 36 | { 37 | string assemblyPath = line.Remove(0, installScriptMagic.Length); 38 | string installScript = GetInstallScriptText(assemblyPath); 39 | sb.AppendLine(installScript); 40 | } 41 | else if (line.StartsWith(uninstallScriptMagic)) 42 | { 43 | string assemblyPath = line.Remove(0, uninstallScriptMagic.Length); 44 | string uninstallScript = GetUninstallScriptText(assemblyPath); 45 | sb.AppendLine(uninstallScript); 46 | } 47 | else if (line.StartsWith(includeFileMagic)) 48 | { 49 | string filePath = line.Remove(0, includeFileMagic.Length); 50 | string fileToInclude = File.ReadAllText(filePath); 51 | sb.AppendLine(fileToInclude); 52 | } 53 | else 54 | { 55 | sb.AppendLine(line); 56 | } 57 | } 58 | } 59 | return sb.ToString(); 60 | } 61 | 62 | private string GetUninstallScriptText(string assemeblyPath) 63 | { 64 | StringBuilder sb = new StringBuilder(); 65 | var asm = Assembly.LoadFile(assemeblyPath); 66 | 67 | IterateScriptableItemsInsideAssembly(asm, item => sb.AppendLine(item.GenerateUninstallScript())); 68 | sb.AppendLine(new InstallerScriptableSqlAssembly(asm).GenerateUninstallScript()); 69 | return sb.ToString(); 70 | } 71 | 72 | private string GetInstallScriptText(string assemeblyPath) 73 | { 74 | StringBuilder sb = new StringBuilder(); 75 | var asm = Assembly.LoadFile(assemeblyPath); 76 | sb.AppendLine(new InstallerScriptableSqlAssembly(asm).GenerateInstallScript()); 77 | IterateScriptableItemsInsideAssembly(asm, item => sb.AppendLine(item.GenerateInstallScript())); 78 | return sb.ToString(); 79 | } 80 | 81 | private void IterateScriptableItemsInsideAssembly(Assembly asm, Action action) 82 | { 83 | var sqlAssembly = new InstallerScriptableSqlAssembly(asm); 84 | 85 | foreach (var method in asm.GetTypes().SelectMany(k => k.GetMembers()).Where(k => k.GetCustomAttributes(false) 86 | .Any(l => l is SqlInstallerScriptGeneratorExportedAttributeBase)) 87 | .OrderBy(k => k.Name)) 88 | { 89 | var attribute = method.GetCustomAttribute(); 90 | var scriptableItem = InstallerScriptableItem.GetScreiptableItem(attribute, sqlAssembly, method); 91 | action(scriptableItem); 92 | 93 | } 94 | 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /InstallerScriptGenerator/Utils/ClrSqlTermsConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace InstallerScriptGenerator.Utils 8 | { 9 | internal static class ClrSqlTermsConverter 10 | { 11 | internal static string ConvertClrTypeToSqlTypeName(Type t) 12 | { 13 | if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) 14 | t = t.GetGenericArguments()[0]; 15 | if (t == typeof(int)) return "int"; 16 | if (t == typeof(long)) return "bigint"; 17 | if (t == typeof(short)) return "smallint"; 18 | if (t == typeof(DateTime)) return "datetime2"; 19 | if (t == typeof(TimeSpan)) return "time"; 20 | if (t == typeof(string)) return "nvarchar(4000)"; 21 | if (t == typeof(bool)) return "bit"; 22 | throw new ArgumentOutOfRangeException("unknown type: " + t.FullName); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # redisql 2 | RediSql is a Redis client for SQL Server (T-SQL) 3 | This is the repository, and can be very useful if you want to read RediSql's code. 4 | 5 | If you're looking for downloads, installation instructions etc. Plase refer to: 6 | http://redisql.ishahar.net 7 | -------------------------------------------------------------------------------- /RediSQLCache.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RediSql", "RedisSqlCache\RediSql.csproj", "{666FE4B7-0A6B-44DF-B179-C394234E33DE}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {CABBBA96-75AF-4F10-96AB-72B814B5A97E} = {CABBBA96-75AF-4F10-96AB-72B814B5A97E} 9 | EndProjectSection 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InstallerScriptGenerator", "InstallerScriptGenerator\InstallerScriptGenerator.csproj", "{CABBBA96-75AF-4F10-96AB-72B814B5A97E}" 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlClrDeclarations", "SqlClrDeclarations\SqlClrDeclarations.csproj", "{56C24720-8053-4CF5-8BF8-BAE7DBA78424}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Checks", "Checks\Checks.csproj", "{A726DF9E-E4F2-470E-8E4D-B8A760D80653}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {666FE4B7-0A6B-44DF-B179-C394234E33DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {666FE4B7-0A6B-44DF-B179-C394234E33DE}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {666FE4B7-0A6B-44DF-B179-C394234E33DE}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {666FE4B7-0A6B-44DF-B179-C394234E33DE}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {CABBBA96-75AF-4F10-96AB-72B814B5A97E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {CABBBA96-75AF-4F10-96AB-72B814B5A97E}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {CABBBA96-75AF-4F10-96AB-72B814B5A97E}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {CABBBA96-75AF-4F10-96AB-72B814B5A97E}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {56C24720-8053-4CF5-8BF8-BAE7DBA78424}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {56C24720-8053-4CF5-8BF8-BAE7DBA78424}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {56C24720-8053-4CF5-8BF8-BAE7DBA78424}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {56C24720-8053-4CF5-8BF8-BAE7DBA78424}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {A726DF9E-E4F2-470E-8E4D-B8A760D80653}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {A726DF9E-E4F2-470E-8E4D-B8A760D80653}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {A726DF9E-E4F2-470E-8E4D-B8A760D80653}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {A726DF9E-E4F2-470E-8E4D-B8A760D80653}.Release|Any CPU.Build.0 = Release|Any CPU 39 | EndGlobalSection 40 | GlobalSection(SolutionProperties) = preSolution 41 | HideSolutionNode = FALSE 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /RedisSqlCache/Common/DateTimeUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace RediSql.Common 6 | { 7 | public static class DateTimeUtils 8 | { 9 | private static readonly DateTime BaseLinuxTime = new DateTime(1970, 1, 1); 10 | 11 | public static double ToUnixTime(DateTime dt) 12 | { 13 | return (BaseLinuxTime - dt).TotalSeconds; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /RedisSqlCache/Deployment/BasicUsageSamples.sql: -------------------------------------------------------------------------------- 1 | -- This file includes some samples of using RediSql. 2 | -- For more samples, and full documentation, please visit http://redisql.ishahar.net 3 | 4 | --Get some server info 5 | SELECT * FROM [redisql].[GetServerInfo] ( 6 | 'localhost' --Redis hosted locally 7 | ,default --default port 8 | ,default --no password 9 | ,default --dbid: 0 10 | ) 11 | GO 12 | 13 | --Create string key without expiration 14 | EXEC [redisql].[SetStringValue] 15 | @host = N'localhost', 16 | @port = 6379, 17 | @key = 'SimpleStringKey', 18 | @value = N'sample_value' 19 | 20 | --We can check if the key exists now 21 | IF (SELECT [redisql].[IsKeyExists] ('localhost',default,default,default,'SimpleStringKey')) = 1 22 | BEGIN 23 | PRINT 'Key Exists!' 24 | END 25 | 26 | --We can add keys with expiration, in the following snippet - 10 minutes 27 | EXEC [redisql].[SetStringValue] 28 | @host = N'localhost', 29 | @port = 6379, 30 | @key = 'StringKeyWithTTL', 31 | @value = N'gv', 32 | @expiration = '00:10:00' --10 minutes expiration 33 | 34 | --Let's print the value of the key 35 | --if the key not exists we'll get NULL value 36 | SELECT [redisql].[GetStringValue] ( 37 | 'localhost' 38 | ,default --default port 39 | ,default -- no password 40 | ,default -- dbid: 0 41 | ,'SimpleStringKey') 42 | 43 | --Delete 'SimpleStringKey' from Redis 44 | SELECT [redisql].[DeleteKey] ( 45 | 'localhost' 46 | ,default --default port 47 | ,default -- no password 48 | ,default -- dbid: 0 49 | ,'SimpleStringKey') 50 | 51 | 52 | --If the key exists in Redis server, just return the value from the server (and extend expiration, if required). 53 | --If the key doesn't exists, store the key in Redis and return it. 54 | SELECT [redisql].[GetSetStringValue] ( 55 | 'localhost' 56 | ,default --port 57 | ,default --pasword 58 | ,default --db 59 | ,'SampleStringKey5' 60 | ,'SampleValue' 61 | ,default --no expiration 62 | ) 63 | 64 | 65 | --Get all keys from Redis. 66 | --not meant for production code, but mostly for debugging 67 | SELECT * FROM [redisql].[GetKeys] ( 68 | 'localhost' 69 | ,default 70 | ,default 71 | ,default 72 | ,'*' -- get all keys, no filter 73 | ) 74 | 75 | --Get all keys from Redis that contains "String" in the key name. 76 | --not meant for production code, but mostly for debugging 77 | SELECT * FROM [redisql].[GetKeys] ( 78 | 'localhost' 79 | ,default 80 | ,default 81 | ,default 82 | ,'*String*' 83 | ) 84 | 85 | --Commit all changes to Redis, by producing point-in-time snapshot 86 | --For further information about persistency in Redis please refer to: 87 | --http://redis.io/topics/persistence 88 | EXEC [redisql].[SaveChanges] 89 | @host = 'localhost' 90 | 91 | --store the result of the query in Redis 92 | EXEC [redisql].StoreQueryResultsData 93 | @host = N'localhost', 94 | @port = 6379, 95 | @key = 'RowsetKey1', 96 | @query = N'SELECT * FROM INFORMATION_SCHEMA.ROUTINES', 97 | @replaceExisting = 1 98 | 99 | --store the result of the query in Redis, but with 50 seconds expiration 100 | EXEC [redisql].StoreQueryResultsData 101 | @host = N'localhost', 102 | @port = 6379, 103 | @key = 'RowsetKey7', 104 | @query = N'SELECT * FROM INFORMATION_SCHEMA.ROUTINES', 105 | @replaceExisting = 1, 106 | @expiration = '00:00:50' 107 | 108 | 109 | --Get the results of the query we stored before 110 | --If key not exists, return null 111 | DECLARE @result int 112 | EXEC @result = [redisql].[GetStoredRowset] 113 | @host = N'localhost', 114 | @key ='RowsetKey1' 115 | PRINT @result --if result >= 0: there was a key that name, with rows, and result is the number of the rows stored. 116 | --if result == -1, key not exists 117 | 118 | --If the key exists in Redis, return the stored rowset 119 | --If the key doesn't exists, run the query, return the results and also store them in Redis 120 | DECLARE @result int 121 | EXEC @result= [redisql].GetSetStoredRowset 122 | @host = N'localhost', 123 | @port = 6379, 124 | @key = 'RowsetKey9', 125 | @query = N'SELECT * FROM INFORMATION_SCHEMA.ROUTINES' 126 | 127 | PRINT @result --if result >= 0: there was a key that name, with rows, and result is the number of the rows stored. 128 | --if result == -1, key not exists and the query executed against SQL Server -------------------------------------------------------------------------------- /RedisSqlCache/Deployment/Install.Sql: -------------------------------------------------------------------------------- 1 | --RediSql - Redis client for T-SQL 2 | --For installation instructions and other information, please visit http://redisql.ishahar.net 3 | 4 | --REMEMBER: make sure you run this query on the correct database! 5 | 6 | DECLARE @dbName nvarchar(50) = '[check1]' --CHANGE HERE TO YOUR DB NAME 7 | 8 | EXEC('ALTER DATABASE ' + @dbname + ' SET TRUSTWORTHY ON') 9 | 10 | 11 | GO 12 | CREATE SCHEMA [redisql] AUTHORIZATION [dbo] 13 | GO 14 | 15 | CREATE ASSEMBLY [SqlClrDeclarations] 16 | AUTHORIZATION [dbo] 17 | FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010300920141560000000000000000E00022200B013000000E000000060000000000001E2C0000002000000040000000000010002000000002000004000000000000000400000000000000008000000002000000000000030040850000100000100000000010000010000000000000100000000000000000000000CB2B00004F00000000400000C803000000000000000000000000000000000000006000000C000000482B00001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000240C000000200000000E000000020000000000000000000000000000200000602E72737263000000C8030000004000000004000000100000000000000000000000000000400000402E72656C6F6300000C0000000060000000020000001400000000000000000000000000004000004200000000000000000000000000000000FF2B0000000000004800000002000500D4200000740A000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E027B010000042A2202037D010000042A5602280800000602032807000006020428050000062A1E027B020000042A2202037D020000042A1E027B030000042A2202037D030000042A1E02281100000A2A1E027B040000042A2202037D040000042A1E027B050000042A2202037D050000042A1E027B060000042A2202037D060000042A42534A4201000100000000000C00000076342E302E33303331390000000005006C00000030040000237E00009C0400007C04000023537472696E6773000000001809000004000000235553001C0900001000000023475549440000002C0900004801000023426C6F6200000000000000020000015715A0010900000000FA01330016000001000000140000000500000006000000100000000A000000110000002300000003000000060000000C000000010000000100000000006D030100000000000600A002010406000D0301040600BE01CF030F00210400000600E6018B0306006D028B0306004E028B030600F4028B030600C0028B030600D9028B030600FD018B030600D201E20306009801E203060031028B030600180253030600610484030600A601840306007D0101040600210384030600720484030000000001000000000001000100010010009D0330040C0001000100010010004C0130044D0002000400010010001F0130040C0004000900010010008A0230044D0004000A0001005E00290001002900290001001300290001007D002C000100130029000100450029005020000000008608FB002F00010058200000000086080D01100001006120000000008618C903330002007720000000008608AD002F0004007F20000000008608BC001000040088200000000086089B002F0005009020000000008608A400100005009920000000008618C903060006006120000000008618C90333000600A1200000000086082B0339000800A9200000000086083C033D000800B2200000000086089B002F000900BA20000000008608A40010000900C320000000008608E3002F000A00CB20000000008608EF0010000A009920000000008618C90306000B00000001004D0300000100D60000000200CB00000001004D03000001004D0300000100D60000000200CB00000001004D03000001004D03000001004D030900C90301001100C90306001900C9030A002900C90310003100C90310003900C90310004100C90310004900C90310005100C90310005900C90310006100C90315006900C90310007100C90310007900C90310008900C9031A009100C90306009900C90306002000830030012100830030012E000B004A002E00130053002E001B0072002E0023007B002E002B0093002E00330093002E003B0093002E0043007B002E004B0099002E00530093002E005B0093002E006300B1002E006B00DB002E007300E80040008300300141008300300143007B00350161008300300180008300300181008300300183007B003501A00083003001A10083003001A3007B003E01C00083003001C10083003001E00083003001400183003001600183003001800183003001A00183003001C00183003001E001830030010200010003000200050004000000110142000000C00042000000DE0042000000400346000000DE0042000000F300420002000100030001000200030002000400050001000500050002000600070001000700070002000A00090001000B00090002000C000B0001000D000B0002000E000D0001000F000D000480000001000000000000000000000000004E04000004000000000000000000000020000A00000000000000003C4D6F64756C653E006D73636F726C6962003C4E616D653E6B5F5F4261636B696E674669656C64003C536368656D614E616D653E6B5F5F4261636B696E674669656C64003C53716C547970653E6B5F5F4261636B696E674669656C64003C53716C52657475726E547970653E6B5F5F4261636B696E674669656C64003C44656661756C7456616C75653E6B5F5F4261636B696E674669656C64006765745F4E616D65007365745F4E616D65006765745F536368656D614E616D65007365745F536368656D614E616D6500736368656D614E616D650066756E6374696F6E4E616D65006765745F53716C54797065007365745F53716C54797065006765745F53716C52657475726E54797065007365745F53716C52657475726E547970650053716C496E7374616C6C657253637269707447656E657261746F724578706F7274656450726F6365647572650053716C496E7374616C6C657253637269707447656E657261746F724578706F727465644174747269627574654261736500436F6D70696C657247656E65726174656441747472696275746500477569644174747269627574650041747472696275746555736167654174747269627574650044656275676761626C6541747472696275746500436F6D56697369626C6541747472696275746500417373656D626C795469746C6541747472696275746500417373656D626C7954726164656D61726B417474726962757465005461726765744672616D65776F726B41747472696275746500417373656D626C7946696C6556657273696F6E41747472696275746500417373656D626C79436F6E66696775726174696F6E41747472696275746500417373656D626C794465736372697074696F6E4174747269627574650053716C506172616D6574657241747472696275746500436F6D70696C6174696F6E52656C61786174696F6E7341747472696275746500417373656D626C7950726F6475637441747472696275746500417373656D626C79436F7079726967687441747472696275746500417373656D626C79436F6D70616E794174747269627574650052756E74696D65436F6D7061746962696C697479417474726962757465006765745F44656661756C7456616C7565007365745F44656661756C7456616C75650076616C75650053797374656D2E52756E74696D652E56657273696F6E696E670053716C436C724465636C61726174696F6E732E646C6C0053797374656D0053797374656D2E5265666C656374696F6E0053716C496E7374616C6C657253637269707447656E657261746F724578706F7274656446756E6374696F6E002E63746F720053797374656D2E446961676E6F73746963730053797374656D2E52756E74696D652E496E7465726F7053657276696365730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300446562756767696E674D6F6465730053716C436C724465636C61726174696F6E732E417474726962757465730053716C436C724465636C61726174696F6E730041747472696275746554617267657473004F626A6563740000000000000000FF1810DC4E0B8B4D9CE1E63AF2E8B1CE00042001010803200001052001011111042001010E042001010205200101114108B77A5C561934E08902060E02061C0320000E052002010E0E0320001C042001011C0328000E0328001C0801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F7773010801000200000000001701001253716C436C724465636C61726174696F6E73000005010000000017010012436F7079726967687420C2A920203230313500002901002435366332343732302D383035332D346366352D386266382D62616537646261373834323400000C010007312E302E302E3000004701001A2E4E45544672616D65776F726B2C56657273696F6E3D76342E300100540E144672616D65776F726B446973706C61794E616D65102E4E4554204672616D65776F726B20340401000000080100400000000000080100000800000000000000000092014156000000000200000067000000642B0000640D000052534453C76A21CD3E8DBE4F9C2BADE7D46D4BFF01000000433A5C50726F6A656374735C5265646953514C43616368655C53716C436C724465636C61726174696F6E735C6F626A5C52656C656173655C53716C436C724465636C61726174696F6E732E70646200F32B000000000000000000000D2C0000002000000000000000000000000000000000000000000000FF2B0000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C000000000000FF25002000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001001000000018000080000000000000000000000000000001000100000030000080000000000000000000000000000001000000000048000000584000006C03000000000000000000006C0334000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE00000100000001000000000000000100000000003F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B004CC020000010053007400720069006E006700460069006C00650049006E0066006F000000A802000001003000300030003000300034006200300000001A000100010043006F006D006D0065006E007400730000000000000022000100010043006F006D00700061006E0079004E0061006D00650000000000000000004E0013000100460069006C0065004400650073006300720069007000740069006F006E0000000000530071006C0043006C0072004400650063006C00610072006100740069006F006E00730000000000300008000100460069006C006500560065007200730069006F006E000000000031002E0030002E0030002E00300000004E001700010049006E007400650072006E0061006C004E0061006D0065000000530071006C0043006C0072004400650063006C00610072006100740069006F006E0073002E0064006C006C00000000004800120001004C006500670061006C0043006F007000790072006900670068007400000043006F0070007900720069006700680074002000A90020002000320030003100350000002A00010001004C006500670061006C00540072006100640065006D00610072006B00730000000000000000005600170001004F0072006900670069006E0061006C00460069006C0065006E0061006D0065000000530071006C0043006C0072004400650063006C00610072006100740069006F006E0073002E0064006C006C0000000000460013000100500072006F0064007500630074004E0061006D00650000000000530071006C0043006C0072004400650063006C00610072006100740069006F006E00730000000000340008000100500072006F006400750063007400560065007200730069006F006E00000031002E0030002E0030002E003000000038000800010041007300730065006D0062006C0079002000560065007200730069006F006E00000031002E0030002E0030002E0030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000C000000203C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 18 | WITH PERMISSION_SET = UNSAFE 19 | 20 | 21 | GO 22 | 23 | CREATE ASSEMBLY [RediSql] 24 | AUTHORIZATION [dbo] 25 | FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010300C1A344560000000000000000E00022200B013000006E00000006000000000000BA8C00000020000000A000000000001000200000000200000400000000000000040000000000000000E000000002000000000000030040850000100000100000000010000010000000000000100000000000000000000000678C00004F00000000A00000680300000000000000000000000000000000000000C000000C000000F48B00001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000C06C000000200000006E000000020000000000000000000000000000200000602E727372630000006803000000A000000004000000700000000000000000000000000000400000402E72656C6F6300000C00000000C00000000200000074000000000000000000000000000040000042000000000000000000000000000000009B8C000000000000480000000200050054430000A0480000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013300500400000000000000002188D3500000125161F0D9C25171F0A9C7D0A00000402281900000A032D0B7201000070731A00000A7A02032805000006020428070000060215280D0000062A36020320EB18000028010000062A4602720B00007020EB18000028010000062A1E027B030000042A2202037D030000042A1E027B040000042A2202037D040000042A1E027B050000042A2202037D050000042A1E027B060000042A2202037D060000042A1E027B070000042A2202037D070000042A1E027B080000042A2202037D080000042A1E027B090000042A9E02037D0900000402721F000070178D110000012516027B090000048C37000001A228280000062A220203281C0000062A2602030428140000062ABE032D0B722D000070731A00000A7A042D0B7235000070731A00000A7A0203281B00000A046F1C00000A28150000062A000000133007006000000000000000032D0B722D000070731A00000A7A042D0B7235000070731A00000A7A048E692000000040311072410000707235000070731D00000A7A02047263000070178D11000001251603A228230000062D0B726B000070731E00000A7A0228270000062ABE032D0B722D000070731A00000A7A042D0B7235000070731A00000A7A0203281B00000A046F1C00000A28170000062A133007005300000000000000032D0B722D000070731A00000A7A042D0B7235000070731A00000A7A048E692000000040311072410000707235000070731D00000A7A0204728F000070178D11000001251603A22829000006163002162A172A00133005005900000000000000032D0B729B000070731A00000A7A02037E25000004252D17267E24000004FE069E000006731F00000A2580250000047E26000004252D17267E24000004FE069F000006732000000A258026000004280100002B28190000062AAE032D0B729B000070731A00000A7A02036F2200000A280200002B036F2400000A280300002B281A0000062A000000133005001E01000001000011038E69048E692E0B72A5000070732500000A7A281B00000A72F50000706F1C00000A0A732600000A0B160C38B6000000281B00000A03089A6F1C00000A0D04089A1304281B00000A72FB000070098E698C3700000172F5000070282700000A6F1C00000A1305281B00000A03089A72F5000070282800000A6F1C00000A1306281B00000A72FB00007011048E698C3700000172F5000070282700000A6F1C00000A13070711051611058E696F2900000A0711061611068E696F2900000A0711071611078E696F2900000A0711041611048E696F2900000A070616068E696F2900000A0817580C08038E693F41FFFFFF02076F2A00000A72FF000070038E69185A17588C370000017203010070282700000A2824000006260228270000062A92032D0B722D000070731A00000A7A02721D010070178D11000001251603A2282D0000062A00133002002700000002000011032D0B722D000070731A00000A7A0203281B0000060A062C0C281B00000A066F2B00000A2A142A6602036F67000006036F73000006036F77000006281E0000062A000000133005006500000003000011032D0B722D000070731A00000A7A04282C00000A2D03192B01170A06058E69588D110000010B071603A205160706058E69282D00000A0617330D0272250100700728480000062A0717722F010070A2071804A202722501007007282A0000068D0400001B2A000000133007006000000000000000032D0B722D000070731A00000A7A042D0B7235000070731A00000A7A048E692000000040311072410000707235000070731D00000A7A0204723B010070178D11000001251603A228230000062D0B726B000070731E00000A7A02282E0000062A133004004000000002000011032D0B722D000070731A00000A7A042D0B7235000070731A00000A7A0203281B00000A046F1C00000A281F0000060A062C0C281B00000A066F2B00000A2A142A133002003200000004000011732E00000A0A2B13071F0D2E0E071F0A2E190607D16F2F00000A26027B020000046F3000000A250B1533DD066F3100000A2A000013300600A0000000000000000218171C733200000A7D01000004027B01000004176F3300000A027B0100000402280C0000066F3400000A027B010000040228040000060228060000066F3500000A027B010000046F3600000A2D13027B010000046F3700000A02147D010000042A02027B01000004733800000A2000400000733900000A7D0200000402280E0000062C1A027249010070178D11000001251602280E000006A228280000062A13300400E90000000500001172FF00007017058E695817580B1201283A00000A72F5000070283B00000A0A1C8D11000001251606A2251772FB000070A22518046F3C00000A8C37000001A2251972F5000070A2251A04A2251B72F5000070A2283D00000A0A050C160B2B5008079A6F3100000A0D281B00000A096F3E00000A13041C8D11000001251606A2251772FB000070A2251811048C37000001A2251972F5000070A2251A09A2251B72F5000070A2283D00000A0A0717580B07088E6932AA1A8D11000001251606A2251772FB000070A22518038E698C37000001A2251972F5000070A2283D00000A0A02030628240000062A0000001B3003007C00000006000011027B010000042D06022822000006027B010000042D02162A281B00000A046F1C00000A0A027253010070042826000006027B01000004066F3F00000A26032C1F027B01000004036F3F00000A26027B01000004027B0A0000046F3F00000A26DE1726027B010000046F3700000A02147D01000004160BDE02172A072A01100000000024003D6100171A0000011B3004001201000007000011027B010000042D06022822000006027B010000042D02162A72FF00007017048E69580C1202283A00000A72F5000070283B00000A0A1C8D11000001251606A2251772FB000070A22518036F3C00000A8C37000001A2251972F5000070A2251A03A2251B72F5000070A2283D00000A0A040D160C2B5309089A6F3100000A1304281B00000A11046F3E00000A13051C8D11000001251606A2251772FB000070A2251811058C37000001A2251972F5000070A2251A1104A2251B72F5000070A2283D00000A0A0817580C08098E6932A7281B00000A066F1C00000A0B027253010070062826000006027B01000004076F3F00000A26DE1826027B010000046F3700000A02147D01000004161306DE02172A11062A0000011000000000DA001BF500181A0000019A037257010070046F4000000A72F5000070725D0100706F4100000A283B00000A284200000A2A00133004006600000008000011027B020000046F3000000A0A0615330B726101007073990000067A0228210000060B02727B01007006D10C1202FE16450000016F3100000A07282800000A2826000006061F2D331D07727F0100706F4300000A2D03072B07071A6F4400000A73990000067A2A7202030428250000062D0B726B000070731E00000A7A0228270000062A0013300400A3000000090000110203040528230000062D0B726B000070731E00000A7A027B020000046F3000000A0A0615330B726101007073990000067A0228210000060B02727B01007006D10C1202FE16450000016F3100000A07282800000A2826000006061F2D331D07727F0100706F4300000A2D03072B07071A6F4400000A73990000067A061F3A330C071203284500000A2C02092A7289010070068C3700000107282700000A73990000067A0013300400A20000000900001102030428250000062D0B726B000070731E00000A7A027B020000046F3000000A0A0615330B726101007073990000067A0228210000060B02727B01007006D10C1202FE16450000016F3100000A07282800000A2826000006061F2D331D07727F0100706F4300000A2D03072B07071A6F4400000A73990000067A061F3A330C071203284500000A2C02092A7289010070068C3700000107282700000A73990000067A000013300400980000000800001102030428250000062D0B726B000070731E00000A7A027B020000046F3000000A0A0615330B726101007073990000067A0228210000060B02727B01007006D10C1202FE16450000016F3100000A07282800000A2826000006061F2D331D07727F0100706F4300000A2D03072B07071A6F4400000A73990000067A061F2B3302072A7289010070068C3700000107282700000A73990000067A7202030428250000062D0B726B000070731E00000A7A0228210000062A7202030428250000062D0B726B000070731E00000A7A02282E0000062A000013300500F60000000A0000110228210000060A02727B010070062826000006066F3C00000A2D0B72CF01007073990000067A06166F4600000A251F2D33230672F70100706F4300000A2D0906176F4400000A2B07061B6F4400000A73990000067A1F244089000000067203020070284700000A2C02142A06176F4400000A1201284500000A2C5F078D350000010C160D027B0200000408090709596F4800000A13041104172F0B720B02007073990000067A091104580D090732D5027B020000046F3000000A1F0D330F027B020000046F3000000A1F0A2E0B724902007073990000067A082A727102007073990000067A728F02007006282800000A73990000067A9E032D0B722D000070731A00000A7A0272B5020070178D11000001251603A2282A00000617FE012A9E032D0B722D000070731A00000A7A0272C3020070178D11000001251603A2282A00000617FE012A6E032D0B72CB020070731A00000A7A0272C302007003282A0000062A92032D0B722D000070731A00000A7A0272D5020070178D11000001251603A2282A0000062AB6032D0B722D000070731A00000A7A0272DF020070188D11000001251603A22517048C37000001A2282A0000062A92032D0B722D000070731A00000A7A0272ED020070178D11000001251603A2282A0000062AB6032D0B722D000070731A00000A7A0272F7020070188D11000001251603A22517048C37000001A2282A0000062A133006008B0000000B000011032D0B722D000070731A00000A7A027205030070178D11000001251603A2282B0000060A06720F030070284700000A2D43067219030070284700000A2D38067227030070284700000A2D2D06722F030070284700000A2D22067239030070284700000A2D17067243030070284700000A2D0C2B0C162A172A192A182A1B2A1A2A724D03007073990000067A4A027269030070168D11000001282B0000062A0000133006004000000000000000032D0B727D030070731A00000A7A042D0B7293030070731A00000A7A0272A9030070188D11000001251603A2251704A2282C000006166F4600000A1F2BFE012AC2032D0B722D000070731A00000A7A0272B7030070188D11000001251603A22517048C37000001A2282A00000617FE012AC2032D0B722D000070731A00000A7A0272C5030070188D11000001251603A22517048C37000001A2282A00000617FE012A92032D0B722D000070731A00000A7A0272D7030070178D11000001251603A2282A0000062A4A0272DF030070168D11000001282A0000062A4A0272ED030070168D1100000128280000062A4A0272F7030070168D1100000128280000062A1B300300710000000B000011027205040070168D110000012825000006260228210000060A02727B010070062826000006066F3C00000A2D0B72CF01007073990000067A0672F70100706F4300000A2D0906176F4400000A2B07061B6F4400000A73990000067A26027B010000046F3700000A02147D01000004DE002A0000000110000000001200495B00151C0000014A027217040070168D1100000128280000062A4A027229040070168D1100000128280000062A0000133003002D0000000C000011027239040070168D11000001282A0000060A210080B5F7F57F9F08734900000A066C284A00000A284B00000A2A00000013300500740000000D00001102724B040070168D11000001282D0000060A734C00000A0B281B00000A066F2B00000A178D4500000125161F0A9D6F4D00000A0C160D2B3408099A130411041F3A6F4E00000A13051105152E1B0711041611056F4F00000A1104110517586F4400000A6F5000000A0917580D09088E6932C6072A320272FF00007028450000062A92032D0B7255040070731A00000A7A027265040070178D11000001251603A228470000062AAA032D0B726F040070731A00000A7A038E2D0B726F040070732500000A7A0272790400700328480000062A00000013300500320000000E00001102030428480000060A068E698D3D0000010B160C2B140708281B00000A06089A6F2B00000AA20817580C08068E6932E6072A000013300400C60000000F00001102030428250000062D0B726B000070731E00000A7A027B020000046F3000000A0A0615330B726101007073990000067A0228210000060B02727B01007006D10C1202FE16450000016F3100000A07282800000A2826000006061F2D331D07727F0100706F4300000A2D03072B07071A6F4400000A73990000067A061F2A3330071203284500000A2C26098D0400001B13041613052B111104110502282E000006A211051758130511050932EA11042A7283040070068C3700000107282700000A73990000067AA20272C5040070198D11000001251603A22517048C37000001A22518058C37000001A228480000062A4E0203281B00000A046F1C00000A284B0000062A7A020472D3040070178D11000001251603A22823000006260228270000062A4E0203281B00000A046F1C00000A284D0000062A7A020472DF040070178D11000001251603A22823000006260228270000062A5A0272EB040070178D11000001251603A2282A0000062A9A0272F5040070188D11000001251603A22517048C37000001A228250000062602282E0000062A76027203050070178D11000001251603A228250000062602282E0000062A7602720D050070178D11000001251603A228250000062602282E0000062A6A02047217050070178D11000001251603A2282900000616FE022A4E0203281B00000A046F1C00000A28520000062A5A027221050070178D11000001251603A2282A0000062A6A0204722D050070178D11000001251603A2282900000616FE022A4E0203281B00000A046F1C00000A28550000062A5A027241050070178D11000001251603A228480000062A5A027253050070178D11000001251603A2282D0000062A5A02726B050070178D11000001251603A2282D0000062A6A02047275050070178D11000001251603A2282900000616FE022A4E0203281B00000A046F1C00000A285A0000062A5A032D06735100000A7A02727F0500700328480000062AAA03282C00000A2C0B728D050070731A00000A7A042D0B726F040070731A00000A7A02030428280000062A3602729505007003285D0000062A5A032D06735100000A7A0272AD0500700328480000062A360272BB05007003285D0000062A5A032D06735100000A7A0272D30500700328480000062A360272DF05007003285D0000062A7A020572F5050070188D11000001251603A2251704A2282900000616FE022A3A02176F6600000602285200000A2A1B300200110000000000000002166F66000006DE0702281000000ADC2A00000001100000020000000909000700000000BA032C2A027201060070168D11000001282500000626022827000006027B010000046F3700000A02147D010000042A1E027B0C0000042A2202037D0C0000042A1E027B0D0000042A2202037D0D0000042A1E027B0E0000042A2202037D0E0000042A1E027B0F0000042A2202037D0F0000042A1E027B100000042A2202037D100000042A1E027B110000042A2202037D110000042A1E027B120000042A2202037D120000042A1E027B130000042A2202037D130000042A0013300200AD00000010000011735300000A0A02286D0000062D0802286F0000062C3006720B0600706F5400000A260602286D0000068C370000016F5400000A260602286F0000068C370000016F5400000A2602286B0000062C0C0672170600706F5400000A26022871000006282C00000A2D190672230600706F5400000A26060228710000066F5400000A26022875000006282C00000A2D1906721D0100706F5400000A26060228750000066F5400000A26066F5500000A2A1E02281900000A2A0000001B30040025000000110000110203040528960000060A060E040E050E066F490000060BDE0A062C06066F5600000ADC072A0000000110000002000A000F19000A00000000133003001E0000000200001102740400001B0A03281B00000A066F2B00000A285700000A812C0000012A00001B3004002D000000120000110203040528960000060A281B00000A060E040E056F4F0000066F2B00000A0BDE0A062C06066F5600000ADC072A0000000110000002000A001721000A000000001B3004002B000000120000110203040528960000060A281B00000A060E046F500000066F2B00000A0BDE0A062C06066F5600000ADC072A000110000002000A00151F000A000000001B3004002B000000120000110203040528960000060A281B00000A060E046F510000066F2B00000A0BDE0A062C06066F5600000ADC072A000110000002000A00151F000A000000001B30040053000000130000110203040528960000060A0E062C0C060E040E056F4C0000062B0A060E040E056F4A0000060F07285800000A2C19060E040F07285900000A0B1201285A00000A696F3900000626DE0A062C06066F5600000ADC2A000110000002000A003E48000A000000001B30040021000000140000110203040528960000060A060E046F4E0000060BDE0A062C06066F5600000ADC072A0000000110000002000A000B15000A000000001B300400DF0000001500001173A00000060A06027D2700000406037D2800000406047D2900000406057D2A000004060E047D2B0000040E0528810000060B067B27000004067B28000004067B29000004067B2A00000428960000060C08067B2B0000046F2F0000062C1E0E072C0F08067B2B0000046F30000006262B0B7229060070731E00000A7A076F5B00000A1758735C00000A2528830000066F5D00000A25076F5E00000A06FE06A1000006735F00000A6F6000000A0F06285800000A2C1D08067B2B0000040F06285900000A0D1203285A00000A696F3900000626DE0A082C06086F5600000ADC2A00011000000200500084D4000A000000001B300400C800000016000011736100000A0A72B2060070736200000A0B076F6300000A06070228820000066F5D00000A0207736400000A0C086F6500000A0D2B6972E2060070286600000A736700000A13041613052B3C0911056F6800000A2D2C110472EC060070110517588C37000001286900000A286600000A0911056F6A00000A736B00000A6F6C00000A1105175813051105096F6D00000A32BA0611046F3100000A6F5D00000A096F6E00000A2D8FDE1E092C06096F5600000ADC082C06086F5600000ADC072C06076F5600000ADC062A012800000200330075A8000A0000000002002C0086B2000A0000000002001100ABBC000A000000001B300800D90000001700001172F006007002736400000A0A061A6F6F00000A066F7000000A722A070070036F7100000A267234070070286600000A736700000A0B066F6500000A0C2B72077254070070286600000A198D1100000125167262070070286600000A08726E0700706F7200000A737300000AA22517728C070070286600000A08728C0700706F7200000A737300000AA225187296070070286600000A0872A60700706F7200000A737300000AA2737400000A6F6C00000A086F6E00000A2D86DE0A082C06086F5600000ADC076F3100000A0DDE0A062C06066F5600000ADC092A000000011C000002003C007EBA000A0000000002000C00C1CD000A000000001A72C80700702A001B30040043000000130000110203040528960000060A060E040E056F140000060F06285800000A2C19060E040F06285900000A0B1201285A00000A696F3900000626DE0A062C06066F5600000ADC2A000110000002000A002E38000A000000001B3004004C000000180000110203040528960000060A060E040E056F160000060B072C240F06285800000A2C1B060E040F06285900000A0C1202285A00000A696F390000060DDE0E070DDE0A062C06066F5600000ADC092A0110000002000A003640000A000000001B3004004B000000190000110203040528960000060A060E040E056F200000060F06285800000A2C19060E040F06285900000A0B1201285A00000A696F3900000626252D03260E050CDE0A062C06066F5600000ADC082A000110000002000A00353F000A000000001B30040021000000120000110203040528960000060A060E046F1C0000060BDE0A062C06066F5600000ADC072A0000000110000002000A000B15000A000000001B300400210000001A0000110203040528960000060A060E046F2F0000060BDE0A062C06066F5600000ADC072A0000000110000002000A000B15000A000000001B300600E50000001B0000110203040528960000060A060E046F360000060B074506000000050000001A0000002F0000006C000000900000007E000000389D000000160C1202FE16040000026F3100000A0DDD98000000170C1202FE16040000026F3100000A0DDD83000000020304050E0416287B00000628830000061B6F7500000A2C12190C1202FE16040000026F3100000A0DDE58180C1202FE16040000026F3100000A0DDE461A0C1202FE16040000026F3100000A0DDE341A0C1202FE16040000026F3100000A0DDE221B0C1202FE16040000026F3100000A0DDE10737600000A7A062C06066F5600000ADC092A0000000110000002000A00CFD9000A000000001B300400230000001A0000110203040528960000060A060E040E056F380000060BDE0A062C06066F5600000ADC072A000110000002000A000D17000A000000001B300400290000001A0000110203040528960000060A060E040F05285A00000A696F390000060BDE0A062C06066F5600000ADC072A0000000110000002000A00131D000A000000001B300400290000001A0000110203040528960000060A060E040E052897000006696F3A0000060BDE0A062C06066F5600000ADC072A0000000110000002000A00131D000A000000001B300400370000001C0000110203040528960000060A060E046F3B0000060B07162F0B1202FE150900001B082B0607737700000A0CDE0A062C06066F5600000ADC082A000110000002000A00212B000A000000001B300400210000001A0000110203040528960000060A060E046F300000060BDE0A062C06066F5600000ADC072A0000000110000002000A000B15000A000000001B30040021000000110000110203040528960000060A060E046F450000060BDE0A062C06066F5600000ADC072A0000000110000002000A000B15000A000000004A0302743D000001285700000A812C0000012A001B3004001F000000110000110203040528960000060A066F430000060BDE0A062C06066F5600000ADC072A000110000002000A000913000A00000000133002002C0000001D00001102A50A00001B0A031200287800000A285700000A812C000001041200287900000A285700000A812C0000012A1B300400290000001E0000110203040528960000060A0E042C08066F3E000006DE12066F3D000006DE0A062C06066F5600000ADC2A0000000110000002000A00141E000A000000001B3004002E0000001E0000110203040528960000060A0F03287A00000A2C08066F41000006DE12066F40000006DE0A062C06066F5600000ADC2A00000110000002000A001923000A000000001B3004001F0000001F0000110203040528960000060A066F420000060BDE0A062C06066F5600000ADC072A000110000002000A000913000A00000000133002002A0000001E000011020373010000060A042C0706046F0F0000060F03287A00000A2C0D060F03287B00000A6F11000006062A00001330020014000000200000117E1B00000402287C00000A0A1200285A00000A2A4A20B20700001717737D00000A801B0000042A4E0272E4070070281E00000A0203289B0000062A1E027B230000042A2202037D230000042A2E739D00000680240000042A220F01287800000A2A4A281B00000A0F01287900000A6F1C00000A2A133008002F00000021000011027B27000004027B28000004027B29000004027B2A000004027B2B00000403171200FE150600001B06287E0000062A0042534A4201000100000000000C00000076342E302E33303331390000000005006C000000481E0000237E0000B41E0000FC12000023537472696E677300000000B03100000408000023555300B4390000100000002347554944000000C4390000DC0E000023426C6F620000000000000002000001571FA20B090A000000FA01330016000001000000520000000F0000002B000000A10000001A010000010000007D0000000F000000D100000021000000040000001500000026000000010000000A00000001000000060000000400000003000000000005090100000000000600A606D00C06002707D00C06006D05680C0F00F00C000006009505EE0906005C06EE0906002806EE0906000E07EE090600C606EE090600DF06EE090600C205EE0906008105B10C06005F05B10C06000B06EE090600DD05220806007906EE0906004D0F800906001A0480090A000A10B90E06003709E40006004405D00C0600B300820106005409E4000600FA0680090600D80BB6110A00E30AB90E0600F605680C0600930AE40006006A0480090600B400820106008C0980090600FB0A800906009D0080090600A400820106005311940D0E005B0A140D12004706400C12009503400C06000E04940D0E009006140D0600D704800906001309800906006000800912003C08FF0C0E00EF04140D1200AC05400C0600910980090600900082011200240A8D1012007E038D101200BC0B8D101600A310870B0600490780090600CD0A800906009700800906001908B6110600F30A80091A000F04970B06006B00820106008200820106006708800906005A09E40006002D1280090A009412B90E0A00C604B90E0A00B904B90E0A004609B90E0600260480090600A30B80090600D70080090600790080091200170A050B16003404870B1200AF0B050B1600210C870B12006803050B1200AD0409011200000A8D1012002C0C8D1016003905870B0600470B800906009F0A800900000000CE00000000000100010001001000590D000045000100010001001000020E000045000C00670001010000D404DB0E7D001400790081011000F40EDB0E45001B00790081011000CC0EDB0E45001B00800081011000E50DDB0E45001B00840081011000A70DDB0E45001B00880081011000C80DDB0E45001B00910080011000320A270B45001B00960081011000660D180B45001B00970002010000D40400007D001C00990002001000BB0A0000810023009900032110006E010000450024009C00030110000100000045002700A00001001110D00301006109D40301009402D80301007E02DB030100C702DB0301006202DB030100AA02DB030100C901D80301006201DB0301004301DE035180AA08E2030100F902D8030100F901E50301002A03E50301004602DB0301002A02DB030100E502D80301000E03D80301001502D80306060101DB0356809208E80356806708E80356805811E80356801810E80356800610E8035680B408E80331007E04EC0306060101DB035680A404F00356806708F00356805811F00356800610F0035680B408F00356807E0FF0030100E301D8033600CA00F40316001600F80316004900070406006F11D80306002711DB030600CB03D80306009D01170406009012D80350200000000086185B0C270101009C200000000086185B0C10000300AA200000000086185B0C06000400BC200000000086085D1116010400C420000000008108661110000400CD20000000008608101112010500D520000000008108191101000500DE20000000008608941112010600E620000000008608A51101000600EF20000000008608E61012010700F720000000008608F51001000700002100000000860874111201080008210000000086088411010008001121000000008608B103160109001921000000008608BE031000090022210000000086084C0112010A002A21000000008608530101000A00522100000000860869091F040B005B2100000000860872091A000C00652100000000860006101A000E0098210000000086000610240410000422000000008600FB002B0412003422000000008600FB00310414009422000000008600061038041600F9220000000086000610420417002823000000008600790F4D0418005224000000008600750F26001A00782400000000860064081F041B00AB24000000008600221156041C00C82400000000860022115E041D003C25000000008600031068042000A825000000008600031072012200F4250000000081009104160124003426000000008100540F06002400E026000000008100580370042400D827000000008100EE00790427007028000000008100720380042900A0290000000081009E081A002B00C829000000008100330E06002D003A2A0000000081002F0E87042D00582A0000000081006D108E042F00082B0000000081007F1097043200B82B0000000081004F089E0434005C2C00000000810060089E043600792C0000000081003401A5043800982C0000000081001501DB003A009A2D0000000086007C1283013A00C22D000000008600C90783013B00EA2D000000008600C907AD043C00062E000000008600B61055013D002B2E000000008600B610B3043E00592E000000008600AC10550140007E2E000000008600AC10B3044100AC2E000000008600EC07B9044300432F000000008600541216014400582F0000000086004D042B044400A42F000000008600DC04BF044600D52F0000000086003D0FBF0448000630000000008600BE0755014A002B30000000008608D00712014B003E30000000008600B90706004B005130000000008600A20706004B006430000000008600600B06004B00F430000000008600FC0806004B0007310000000086005A0106004B001C31000000008608B107C5044B005831000000008600690BCA044B00D831000000008608270FD3044B00E531000000008600300FD8044B000A32000000008600640FDE044C0038320000000086001512E6044D0078320000000086000112EE044F004A330000000086000404F70451007333000000008600B9081A0054008733000000008600B90824045600A633000000008600C2081A005800BA33000000008600C20824045A00D933000000008600E00855015C00F033000000008600D71100055D001734000000008600710B26005F003534000000008600790B260060005334000000008600EA0F310461006E34000000008600EA0F2B0463008234000000008600CB0F550165009934000000008600AD0F31046600B434000000008600AD0F2B046800C834000000008600BB0F07056A00DF34000000008600980F26006B00F634000000008600830F26006C000D35000000008600DC0F31046D002835000000008600DC0F2B046F003C350000000086007C0EDE04710053350000000081007B0C0E0572007E350000000086006B0E150574008C35000000008600A30EDE047500A3350000000086008B0E15057600B135000000008600570EDE047700C835000000008600410E15057800D635000000008600F30F1B057900F53500000000E601220506007C00043600000000C400E30706007C00343600000000C401220515007C006336000000008608331216017D006B360000000086083B1210007D007436000000008608FB072D017E007C360000000086080A0815007E008536000000008608A2122D017F008D36000000008608B61215007F0096360000000086084F10120180009E360000000086085E1001008000A736000000008608311012018100AF36000000008608401001008100B836000000008608E71116018200C036000000008608EE1110008200C9360000000086085E1216018300D1360000000086086D1210008300DA36000000008608690F16018400E236000000008608710F10008400EC360000000086004D0D2A028500A5370000000086185B0C06008500B037000000009600740D23058500F437000000009600F80B35058C002038000000009600C4113E058E006C38000000009600710B4D059400B438000000009600790B4D059900FC380000000096002C115B059E006C39000000009600DD087305A600AC390000000096001E018105AB00A83A00000000910036119905B300A43B0000000091001A09A305B400A83C0000000096087201AB05B600B03C0000000096006A07AF05B600103D000000009600010FC605BD00783D0000000096006707DD05C400E03D00000000960058074D05CB00203E0000000096001B0FF405D000603E000000009600D1044D05D500643F0000000096004D040206DA00A43F000000009600AB091106E000EC3F000000009600C1092206E6003440000000009600DA003206EC0088400000000096004A12F405F100C840000000009600300F4506F60008410000000096000F0C3505FB001C41000000009600690B5506FD005841000000009600E60B640601019041000000009600B90771060401D841000000009600CC087F0609012442000000009600B9018C060D016042000000009300420A9A06110198420000000096007304A8061501B842000000009118610CAE061601CB420000000086185B0C10001601DF42000000008608DC0316011701E742000000008108E50310001701F042000000009118610CAE061801A5370000000086185B0C06001801FC420000000083002000B206180105430000000083005300BD061901A5370000000086185B0C06001A0118430000000083002D0010001A01000001006F11000002002711000001006F11000001009C07000001009C07000001009C07000001009C07000001009C07000001009C07000001009C07000001009012000001009012000002009C07000001009012000002009C07000001009012000002009C07000001009012000002009C07000001009012000002009C07000001005C0F000001005C0F00000100380F00000200460D000001009012000001009012000001000E0E000001009012000002009F09000003000E0E000001009012000002009C07000001009012000002009C07000001004701000002004B0300000300540D00000100470100000200820B000001004B0300000200540D00000100C60100000200F303000001004B0300000200540D000001004701000002004B0300000300540D000001004B0300000200540D000001004B0300000200540D000001004B0300000200540D000001004B0300000200540D00000100901200000100901200000100540D000001009012000001009012000002000411000001009012000001009012000002000411000001009012000001005404000002005F0400000100901200000200A90C000001009012000002008C0400000100901200000100580B00000100380F000001004B0300000200540D000001004B0300000200540D000001009012000002000A11000003009103000001009012000002009C07000001009012000002009C07000001009012000002009C07000001009012000002009C0700000100901200000100901200000200E11100000100901200000100901200000100901200000200A80B00000100901200000200A80B00000100901200000100901200000200A80B00000100901200000200A80B00000100901200000100901200000100901200000100901200000200A80B00000100901200000200A80B00000100380F000001004B0300000200380F00000100380F00000100380F00000100380F00000100380F00000100380F00000100431200000200881200000300A80B000001007808000001009C07000001009C07000001009C07000001009C07000001009C07000001009C07000001009C07000001009C07000001006F1100000200271100000300CB03000004009D01000005009012000006000A11000007009103000001007B09020002009C07000001006F1100000200271100000300CB03000004009D0100000500901200000600E111000001006F1100000200271100000300CB03000004009D01000005009012000001006F1100000200271100000300CB03000004009D01000005009012000001006F1100000200271100000300CB03000004009D01000005009012000006009C07000007004F0300000800D409000001006F1100000200271100000300CB03000004009D01000005009012000001006F1100000200271100000300CB03000004009D0100000500901200000600DC1200000700D40900000800820800000100DC1200000100500A00000200DC12000001006F1100000200271100000300CB03000004009D01000005009012000006009C0700000700D409000001006F1100000200271100000300CB03000004009D01000005009012000006009C0700000700D409000001006F1100000200271100000300CB03000004009D01000005009012000006009C0700000700D409000001006F1100000200271100000300CB03000004009D01000005009012000001006F1100000200271100000300CB03000004009D01000005009012000001006F1100000200271100000300CB03000004009D01000005009012000001006F1100000200271100000300CB03000004009D01000005009012000006003A04000001006F1100000200271100000300CB03000004009D0100000500901200000600D409000001006F1100000200271100000300CB03000004009D0100000500901200000600D409000001006F1100000200271100000300CB03000004009D01000005009012000001006F1100000200271100000300CB03000004009D01000005009012000001006F1100000200271100000300CB03000004009D0100000500390C000001007B09020002004504000001006F1100000200271100000300CB03000004009D01000001007B09020002002E04020003009C07000001006F1100000200271100000300CB03000004009D0100000500A403000001006F1100000200271100000300CB03000004009D01000001006F1100000200271100000300CB03000004009D01000001006F1100000200271110100300CB03101004009D0100000100610F00000100EE03000001009C0700000100F60800000100C21100000100F8080200490009005B0C010011005B0C060019005B0C0A0029005B0C100031005B0C100039005B0C100041005B0C100049005B0C100051005B0C100059005B0C100061005B0C150069005B0C100071005B0C100079005B0C100081005B0C10008900E3070600A9005B0C0600C1005B0C0600D9005B0C100021015B0C1A0029015B0C060041015B0C060069015B0C1A0071015B0C060089005B0C0600B1015B0C1000C101C1002000C101320D2600C9015B0C1A0001015B0C10000C005B0C3A0014005B0C3A00D101CF124F001C00270F8900D1012B1293001C003B0DA500C9015B0C1000B9005B0C0600E901460FC600E901460FCD00F1013305D300B9002B12DB00C1016408E500E901EE12F100F901CA12F600C9005B0C0600C9008E030C01F1014507120189004608160199005B0C1A019900F51115009900841101009900540F27019900AB012D0199001C05060019025B0C3101A1005B0C3701B90146081601E901460F4801E901D2081201E901460F4F01C101D9105501990089036001E90187091601E901D403720121029A047801E901EB088301E9016E088801B9012A059401E901160EA401E901E212A901F101A201AF01E9005B0CBF0179019D0CC401E900870ACB012C005B0C0600E9012B10EC01E901F307F301E9016E08F8012C00A701FE01B1015B0C06003102DB071A0219015B0C06001901A701250219012B122A0291002205060061011F103702340086072D0134004E07550279018C0C5A023C00C01012013C005B0C01003C00A7017B023C00FB03810244005B0C3A003C00A20893023C005B0C060089015B0C100041029A09060091015B0CB4029101CA0BBC0249021F10C202A1015B0CC90251021109D002E901460FD50251029307DB02A1015B0CE0025902A701E8025102CA1012015102A2012D016102A904FA029101200E0103710279070703510269090F0381025B0CE002A1015B0C1403E9015F0D400391025B0C06004C005B0C7B0254003312550254004E076D034C0086072D014C004E075502E900DF098403E9005B0C8E030A002C00A90308005400B20308005800B70308005C00BC0308006000C10308006400C60308006800CB0308007400B20308007800B70308007C00BC0308008000C10308008400C60308008800CB0312004D04B20312005104B2032E000B00E8062E001300F1062E001B0010072E00230019072E002B0026072E00330026072E003B0026072E00430019072E004B002C072E00530026072E005B0026072E00630044072E006B006E072E0073007B0743007B00D00D61008B00B70380008B00B70381008B00B703A0008B00B703A1008B00B703C0008B00B703C1008B00B703E0008B00B703E1008B00B70300018B00B70301018B00B70320018B00B70340018B00B70360018B00B70380018B00B70381018B00B703A0018B00B703A1018B00B703C0018B00B703C1018B00B703C3018B00B703E0018B00B703E1018B00B703E3018B00B70301028B00B70321028B00B70341028B00B70361028B00B703E4039300B70361048B00B703C0049B00C307C4049300B70344059300B703C4059300B70324069300B70364069300B703A4069300B703E4069300B70324079300B70384079300B70384099300B703C4099300B703040A9300B703E00C8B00B703000D8B00B703200D8B00B703400D8B00B703600D8B00B703800D8B00B703A00D8B00B703C00D8B00B703E00D8B00B703000E8B00B703200E8B00B703240E9300B703400E8B00B703600E8B00B703640E9300B703800E8B00B703840E9300B703A00E8B00B703A40E9300B703C00E8B00B703C40E9300B703E40E9300B703040F9300B703200FA300CE07200FAB00E807600FA300DD08600FAB00FE08800FA300A209800FAB00FE08A00FA300BB09A00FAB00FE08C00FBB00D509C00FC300B703E00FA300EC09E00FAB00FE080010BB00070A0010C300B7038010BB002A0A8010C300B703A010A300460AA010AB00FE08C010A3006D0AC010AB00FE08C410B300DA0DE010A3008C0AE010AB00FE08E410B300F40D0011A300A80A0011AB00FE080411B300F40D2011A300C10A2011AB00FE084011A300D90A4011AB00FE084411B300640E6011A300F00A6011AB00FE086411B3007D0E8011A300130B8011AB00FE08A011A300330BA011AB00FE08C011A3004A0BC011AB00FE08E011A300610BE011AB00760BE411B300DA0D0412B300F40D2012A300680C2012AB00830C2412B300F40D6012BB008A0D6012C300B7038012BB00A30D8012C300B703A012A300B60DA012AB00FE08A412B300DA0DC412B300F40DE412B300F40D40138B00B7034413B300DA0D60138B00B7036413B300F40D8413B300F40DE413B300DA0D0414B300F40D2414B300F40D8414B300960EA414B300F40DE414B300DA0D0415B300F40D2415B300F40D8415B300DA0DA415B300F40DC415B300F40D2416B300F40D4416B300AC0EE416B300DA0D0417B300F40D2417B300F40D8417B300F40DC417B300DA0DE417B300F40D0418B300F40D6418B300F40DA418B300DA0DC418B300F40DE418B300F40D4419B300F40D8419B300DA0DA419B300F40DC419B300F40D241AB300DA0D441AB300F40D641AB300F40DC41AB300DA0DE41AB300F40D041BB300F40D641BB300DA0D841BB300F40DA41BB300F40D241CB300DA0D441CB300F40D641CB300F40DE41CB300DA0D041DB300F40D241DB300F40DA41DB300DA0DC41DB300F40DE41DB300F40D441EB300DA0D641EB300F40D841EB300F40DE41EB300DA0D041FB300F40D241FB300F40D441FB300C20EC41FB300DA0DE41FB300F40D0420B300F40DA420B300DA0DC420B300F40DE420B300F40D0421B300960E4421B300DA0D6421B300F40D8421B300F40DC421B300DA0DE421B300F40D0422B300F40DB400E000EB0006013F015A0166017D018D019B01B701BB01D50106020F021F022F023E0244025E0264029E02ED021D0327033003360348035B03720377037E0395030200010003000C00060014000D00150000006A11C90600001D11CD060000A911CD060000F910CD0600008811CD060000C203C90600005F01CD0600007609D1060000D407CD060000B507D6060000330FDB0600008C12C90600000E08E0060000BA12E00600006210CD0600004410CD060000F211C90600007112C9060000750FC90600007601E4060000E903C90602000400030001000500030002000600050001000700050002000800070001000900070002000A00090001000B00090002000C000B0001000D000B0002000E000D0001000F000D00020010000F00010011000F0002001200110001001300110002003C001300020042001500020044001700020067001900010068001900020069001B0001006A001B0002006B001D0001006C001D0002006D001F0001006E001F0002006F00210001007000210002007100230001007200230002007300250001007400250002007500270001007600270002008300290002009A002B0001009B002B000200CA0021002C00400081000301E5014C0274028C02540365030480000001000000000000000000000000002F090000040000000000000000000000A003650100000000040000000000000000000000A0038009000000000100000000000000000000000000810D00000000040000000000000000000000A003090100000000040000000000000000000000A003870B00000000040000000000000000000000A003E304000000000C0002000D0002000E0002000F000600430074004700A1004700AF000000003C3E635F5F446973706C6179436C617373305F30003C3E395F5F34325F30003C5365743E625F5F34325F30003C53746F72655175657279526573756C7473446174613E625F5F30003C3E395F5F34325F31003C5365743E625F5F34325F31004E756C6C61626C6560310049456E756D657261626C65603100416374696F6E60310049436F6C6C656374696F6E6031004C697374603100496E7433320046756E636032004B657956616C7565506169726032004944696374696F6E6172796032006765745F55544638003C3E39003C4D6F64756C653E004743004765744B657954544C0053797374656D2E494F0053656E644461746152455350005365744E580076616C75655F5F0053797374656D2E446174610052656164446174610053746F72655175657279526573756C7473446174610053656E644578706563744461746100656E645F64617461006765745F4462007365745F446200466C7573684462006462006D73636F726C6962003C3E63006765745F526F777365744D616769630053797374656D2E436F6C6C656374696F6E732E47656E657269630064624964005265616400416464006765745F436F6E6E6563746564004765744C6173745361766564006964003C50617373776F72643E6B5F5F4261636B696E674669656C64003C436F64653E6B5F5F4261636B696E674669656C64003C44657363656E64696E673E6B5F5F4261636B696E674669656C64003C4765743E6B5F5F4261636B696E674669656C64003C55707065724C696D69743E6B5F5F4261636B696E674669656C64003C4C6F7765724C696D69743E6B5F5F4261636B696E674669656C64003C5265747279436F756E743E6B5F5F4261636B696E674669656C64003C506F72743E6B5F5F4261636B696E674669656C64003C486F73743E6B5F5F4261636B696E674669656C64003C53656E6454696D656F75743E6B5F5F4261636B696E674669656C64003C526574727954696D656F75743E6B5F5F4261636B696E674669656C64003C42793E6B5F5F4261636B696E674669656C64003C4B65793E6B5F5F4261636B696E674669656C64003C53746F7265496E4B65793E6B5F5F4261636B696E674669656C64003C4C65786F67726170686963616C6C793E6B5F5F4261636B696E674669656C6400636D6400616464546F456E640053656E6444617461436F6D6D616E64004462436F6D6D616E640053656E64436F6D6D616E640053716C436F6D6D616E640053656E6400417070656E6400446174614163636573734B696E640069734261636B67726F756E64006765745F50617373776F7264007365745F50617373776F72640070617373776F7264005265706C616365006765745F436F6465007365745F436F646500636F6465006D6573736167650041646452616E6765004C69737452616E67650049456E756D657261626C650049446973706F7361626C6500436F6E736F6C65007469746C6500584E616D65006B65794E65774E616D65006B65794E616D650052656E616D65006F6C644B65796E616D65006E65774B65796E616D65004461746554696D6500546F556E697854696D6500426173654C696E757854696D650074696D6500526561644C696E650057726974654C696E65004E6F6E65007365745F436F6D6D616E64547970650050726F746F636F6C5479706500536F636B657454797065004765744B657954797065004578706972650053797374656D2E436F72650053716C496E7374616C6C657253637269707447656E657261746F724578706F7274656450726F63656475726500436C6F736500446973706F7365005472795061727365005772697465005841747472696275746500436F6D70696C657247656E65726174656441747472696275746500477569644174747269627574650044656275676761626C6541747472696275746500436F6D56697369626C6541747472696275746500417373656D626C795469746C654174747269627574650053716C50726F63656475726541747472696275746500417373656D626C7954726164656D61726B417474726962757465005461726765744672616D65776F726B41747472696275746500436F6E646974696F6E616C41747472696275746500417373656D626C7946696C6556657273696F6E41747472696275746500417373656D626C79436F6E66696775726174696F6E4174747269627574650053716C46756E6374696F6E41747472696275746500417373656D626C794465736372697074696F6E4174747269627574650044656661756C744D656D6265724174747269627574650053716C506172616D6574657241747472696275746500436F6D70696C6174696F6E52656C61786174696F6E7341747472696275746500417373656D626C7950726F6475637441747472696275746500417373656D626C79436F7079726967687441747472696275746500506172616D417272617941747472696275746500417373656D626C79436F6D70616E794174747269627574650052756E74696D65436F6D7061746962696C697479417474726962757465005265616442797465006765745F56616C756500476574537472696E6756616C756500476574536574537472696E6756616C7565004164645769746856616C7565006765745F48617356616C75650047657456616C75650076616C7565004261636B67726F756E6453617665006765745F4C617374536176650054696D65546F4C6976650052656D6F7665006765745F446253697A6500537570707265737346696E616C697A6500547970654F6600496E6465784F66006765745F44657363656E64696E67007365745F44657363656E64696E6700456E636F64696E670053797374656D2E52756E74696D652E56657273696F6E696E670053716C537472696E6700546F537472696E670053656E64457870656374537472696E670053656E64476574537472696E6700537562737472696E6700646973706F73696E67007265706C6163654578697374696E67004E6F744578697374696E67004C6F6700466F724561636800556E697845706F63680048617368004C656674507573680052696768745075736800466C757368006765745F4C656E677468004765744C6973744C656E6774680053746172747357697468006B0076616C00466C757368416C6C005265646953716C2E646C6C00497344424E756C6C00476574436F6C756D6E4D65746164617461586D6C005265646953716C00427566666572656453747265616D004E6574776F726B53747265616D004D656D6F727953747265616D006273747265616D006765745F4974656D007365745F4974656D006974656D0053797374656D005472696D00456E756D0054696D655370616E004F70656E0064657374696E6174696F6E0053657452656C617469766545787069726174696F6E00536574457861637445787069726174696F6E0065787069726174696F6E006F705F5375627472616374696F6E0053797374656D2E5265666C656374696F6E0053716C506172616D65746572436F6C6C656374696F6E004462436F6E6E656374696F6E0053716C436F6E6E656374696F6E005265646973436F6E6E656374696F6E00476574436F6E6E656374696F6E00636F6E6E656374696F6E0053716C496E7374616C6C657253637269707447656E657261746F724578706F7274656446756E6374696F6E006F705F4164646974696F6E00494F457863657074696F6E00417267756D656E744F75744F6652616E6765457863657074696F6E00526573706F6E7365457863657074696F6E00417267756D656E744E756C6C457863657074696F6E00536F636B6574457863657074696F6E00417267756D656E74457863657074696F6E0053797374656D2E446174612E436F6D6D6F6E005265646953716C2E436F6D6D6F6E005265646953716C2E53716C436C72436F6D706F6E656E74732E436F6D6D6F6E00537472696E67436F6D70617269736F6E007061747465726E0053687574646F776E00476574496E666F004C656674506F70005269676874506F7000726573700053797374656D2E586D6C2E4C696E710053797374656D2E4C696E710043686172006D656D626572004462446174615265616465720053716C44617461526561646572004578656375746552656164657200537472696E674275696C64657200476574496E666F5F526F7746696C6C6572004765744C6973744974656D735F526F7746696C6C6572004765744B6579735F526F7746696C6C65720058436F6E7461696E65720053716C506172616D657465720066696C746572004D6963726F736F66742E53716C5365727665722E536572766572002E63746F72002E6363746F720053797374656D2E446961676E6F73746963730053746F7265536574436F6D6D616E6473006765745F546F74616C5365636F6E64730046726F6D5365636F6E6473007365636F6E64730053797374656D2E52756E74696D652E496E7465726F7053657276696365730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300446562756767696E674D6F6465730053797374656D2E446174612E53716C54797065730053716C436C724465636C61726174696F6E732E41747472696275746573004765744279746573006765745F56616C7565730076616C75657300546F41726773006172677300526564697300457175616C73004461746554696D655574696C73004765744C6973744974656D730053716C436C724465636C61726174696F6E730053797374656D2E436F6C6C656374696F6E73005265646973716C4B6579734D616E6970756C6174696F6E46756E6374696F6E73005265646973716C476C6F62616C53657276657246756E6374696F6E73005265646973716C537472696E6756616C75657346756E6374696F6E7300536F72744F7074696F6E73006F7074696F6E73006765745F4368617273006765745F506172616D65746572730053656E64457870656374537563636573730053746F7265446966666572656E63654F665365747300476574446966666572656E63654F66536574730053746F7265556E696F6E4F665365747300476574556E696F6E4F66536574730053746F7265496E74657273656374696F6E4F665365747300476574496E74657273656374696F6E4F66536574730053797374656D2E4E65742E536F636B657473005265646973716C526F7773657473005265646953716C2E53716C436C72436F6D706F6E656E7473005265646973716C4C6973747300536574537472696E6756616C756549664E6F744578697374730049734B6579457869737473006765745F4B657973004765744B657973006B65797300457870697265417400436F6E636174004F626A65637400436F6E6E6563740064696374006474004D476574006765745F476574007365745F476574004D536574005A53657400506F7052616E646F6D4D656D6265724F665365740047657452616E646F6D4D656D6265724F665365740049734D656D6265724F66536574004765744D656D626572734F665365740043617264696E616C6974794F665365740052656D6F766546726F6D53657400416464546F536574004D6F76654D656D626572546F5365740047657453657400536F636B657400736F636B657400526F77736574006F705F496D706C696369740053706C6974006765745F55707065724C696D6974007365745F55707065724C696D6974006765745F4C6F7765724C696D6974007365745F4C6F7765724C696D69740053656E6444617461457870656374496E740053656E64457870656374496E740053797374656D2E446174612E53716C436C69656E740058456C656D656E740044656372656D656E7400496E6372656D656E74006765745F436F756E74006765745F4669656C64436F756E740047657442797465436F756E74006765745F5265747279436F756E74007365745F5265747279436F756E7400636F756E74007374617274006765745F506F7274007365745F506F727400536F727400706F727400416464546F4C69737400457865637574655175657279416E64476574526573756C744C6973740041727261794C697374006765745F486F7374007365745F486F737400686F7374006765745F53656E6454696D656F7574007365745F53656E6454696D656F7574006765745F526574727954696D656F7574007365745F526574727954696D656F75740053797374656D2E546578740076004765744C6973744974656D4174496E646578004C697374496E64657800696E646578006765745F4279007365745F4279007365745F4E6F44656C61790053656E644578706563744461746141727261790053656E64457870656374537472696E67417272617900546F4172726179006765745F4B6579007365745F4B6579007372634B65790044656C6574654B65790052616E646F6D4B6579006765745F53746F7265496E4B6579007365745F53746F7265496E4B657900436F6E7461696E734B657900646573744B6579006B6579004164647265737346616D696C79006765745F4C65786F67726170686963616C6C79007365745F4C65786F67726170686963616C6C7900436F707900546F44696374696F6E617279007175657279006F705F457175616C6974790049734E756C6C4F72456D70747900000968006F007300740000136C006F00630061006C0068006F0073007400000D530045004C0045004300540000076B0065007900000B760061006C00750065000021760061006C0075006500200065007800630065006500640073002000310047000007530045005400002355006E00610062006C006500200074006F00200063006F006E006E00650063007400000B5300450054004E00580000096400690063007400004F6B00650079007300200061006E0064002000760061006C0075006500730020006D007500730074002000680061007600650020007400680065002000730061006D0065002000730069007A00650000050D000A000003240000032A0000190D000A00240034000D000A004D005300450054000D000A000007470045005400000953004F0052005400000B530054004F0052004500000D470045005400530045005400000941005500540048000003430000053A0020000003200000194E006F0020006D006F0072006500200064006100740061000003530000094500520052002000004555006E006B006E006F0077006E0020007200650070006C00790020006F006E00200069006E0074006500670065007200200072006500710075006500730074003A00200000275A00650072006F0020006C0065006E00670074006800200072006500730070006F0073006500000B2D004500520052002000010724002D003100013D49006E00760061006C006900640020007400650072006D0069006E006100740069006F006E0020006D00690064002000730074007200650061006D00002749006E00760061006C006900640020007400650072006D0069006E006100740069006F006E00001D49006E00760061006C006900640020006C0065006E00670074006800002555006E006500780070006500630074006500640020007200650070006C0079003A002000000D4500580049005300540053000007440045004C0000096100720067007300000949004E0043005200000D49004E00430052004200590000094400450043005200000D4400450043005200420059000009540059005000450000096E006F006E006500000D73007400720069006E006700000773006500740000096C0069007300740000097A0073006500740000096800610073006800001B49006E00760061006C00690064002000760061006C00750065000013520041004E0044004F004D004B004500590000156F006C0064004B00650079006E0061006D00650000156E00650077004B00650079006E0061006D006500000D520045004E0041004D004500000D4500580050004900520045000011450058005000490052004500410054000007540054004C00000D44004200530049005A00450000095300410056004500000D4200470053004100560045000011530048005500540044004F0057004E00001146004C0055005300480041004C004C00000F46004C005500530048004400420000114C004100530054005300410056004500000949004E0046004F00000F7000610074007400650072006E0000094B0045005900530000096B0065007900730000094D00470045005400004155006E006B006E006F0077006E0020007200650070006C00790020006F006E0020006D0075006C00740069002D0072006500710075006500730074003A002000010D4C00520041004E0047004500000B4C005000550053004800000B5200500055005300480000094C004C0045004E00000D4C0049004E0044004500580000094C0050004F0050000009520050004F00500000095300410044004400000B5300430041005200440000135300490053004D0045004D00420045005200001153004D0045004D00420045005200530000175300520041004E0044004D0045004D004200450052000009530050004F00500000095300520045004D00000D530055004E0049004F004E00000763006D0064000017530055004E0049004F004E00530054004F0052004500000D530049004E005400450052000017530049004E00540045005200530054004F0052004500000B53004400490046004600001553004400490046004600530054004F0052004500000B53004D004F005600450000095100550049005400000B4C0049004D0049005400000B41004C005000480041000005420059000080876B00650079002000770069007400680020007400680065002000730061006D00650020006E0061006D006500200061006C007200650061006400790020006500780069007300740073002C00200061006E00640020007200650070006C00610063006500200066006C006100670020006E006F007400200065006E00610062006C0065006400002F63006F006E007400650078007400200063006F006E006E0065006300740069006F006E003D00740072007500650000096900740065006D00000349000039730070005F00640065007300630072006900620065005F00660069007200730074005F0072006500730075006C0074005F0073006500740000097400730071006C00001F43006F006C0075006D006E0073004D006500740061006400610074006100000D43006F006C0075006D006E00000B6F007200640065007200001D63006F006C0075006D006E005F006F007200640069006E0061006C0000096E0061006D006500000F730071006C0054007900700065000021730079007300740065006D005F0074007900700065005F006E0061006D006500001B5200450044004900530051004C0052004F005700530045005400001D52006500730070006F006E007300650020006500720072006F007200000000560591B139EE1E4185920BB5EDA9CF6500042001010803200001052001011111042001010E0420010102052002010E0E0500001280E10520011D050E0D151280850215118089020E0E0E052002011C180E151280850215118089020E0E1D0524100303151279021E011E02151280ED011E0015128085021E001E0115128085021E001E020C0A0315118089020E0E0E1D0507151259020E1D05092000151280F10113000D1001011D1E00151280ED011E00030A010E092000151280F1011301040A011D051107081D05125D081D051D051D051D051D050600030E1C1C1C0500020E0E0E072003011D0508080420001D050407011D050520010E1D05050702081D1C040001020E0C0005011280FD081280FD0808021D05050702126508052001126503032000080320000E0C200301118101118105118109052002010E080320000205200101124D072002011280F9080807050E081D1C0E080600030E0E0E0E0500010E1D1C042001080E0507021D0502052001081D050B07070E1D05081D1C0E08020520020E0E0E040001010E050703080E03042001020E0420010E08060704080E0308060002020E10080807050E081D0508080420010308050002020E0E072003081D0508080307010E03070108042001010A0600011180BD0D090002117511751180BD0F07061D05151279020E0E1D0E080E0806151279020E0E0620011D0E1D0304200108030520020E080807200201130013010807031D1D051D0E080A0706080E03081D1D0508040001011C05070112808D042001081C0420001D1C070702120812809D0600011180B10E05070212080E07070212081180BD08151180AD011180BD04200013000320000D0507021208080F0704123C151280C1010E12081180BD06151280C1010E0520010113000A200101151280ED011300061512811D010E0A2001011512811D011300150706151280C1010E1280C51280C91280CD1280D108072002010E1280C50520001280CD0600011281250E0620010112812504200102080500020E1C1C0420011C08072002011281251C042001011C0C07041280C91280D11280CD0E0620010111813505200012813907200212813D0E1C0420011C0E082002011281251D1C0907041208021180BD0208070312081180BD0E0507021208020907041208113011100E072002020E1181450B0703120808151180AD010806151180AD010809070115118089020E0E0715118089020E0E04200013010407011208060702120811750507011180BD0900021180BD11751175062003010808080A0701151180AD011180BD08B77A5C561934E089080080B5F7F57F9F080400000000040100000004020000000403000000040400000004050000000306124D0306125102060E02060803061D0502060A020602030611100306117503061130030612380E06151280850215118089020E0E0E0F06151280850215118089020E0E1D050706151180AD01080420010E0E062002010E1D05052002020E0E062002020E1D0509200101151259020E0E0A200101151259020E1D05082002011D0E1D1D050720011D1D05120C0920031D1D050E0E1D1C0720021D050E1D05082003021D050E1D1C062002021D050E062002020E1D1C062002010E1D1C082003081D050E1D1C062002080E1D1C0620020E0E1D1C0720021D050E1D1C052001081D0E052002080E0805200111300E052002020E080420001175082000151279020E0E0420001D0E0520011D0E0E0720011D1D051D0E0720021D0E0E1D1C0820021D1D050E1D1C0820031D1D050E08080620021D050E080620011D1D050E062002010E1D0E052001011D0E072003020E0E1D0511000712809D0E080E151180AD01080E0808080002011C101180B10E00060E0E080E151180AD01080E080D00050E0E080E151180AD01080E170008010E080E151180AD01080E0E02151180AD011180BD0D0005080E080E151180AD01080E170008010E080E151180AD01080E0E151180AD011180BD02090001151280C1010E0E0700020E1280C50E0300000E160007010E080E151180AD01080E0E151180AD011180BD160007020E080E151180AD01080E0E151180AD011180BD1600070E0E080E151180AD01080E0E151180AD011180BD0D0005020E080E151180AD01080E0E0006020E080E151180AD01080E0E100006020E080E151180AD01080E1180BD0F0006020E080E151180AD01080E1175120005151180AD01080E080E151180AD01080E0F000512809D0E080E151180AD01080E0E000412809D0E080E151180AD01080C0003011C101180B1101180B10D0005010E080E151180AD0108020C0004010E080E151180AD01080D000411750E080E151180AD01080D000412080E080E151180AD01080500010D1175030000010A20010E15118089020E0E0B20011D0515118089020E0E0328000E032800080428010E0E04280011750428001D0E032800020308000E0801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F7773010801000200000000000C0100075265646953716C000005010000000017010012436F7079726967687420C2A920203230313500002901002436363666653462372D306136622D343464662D623137392D63333934323334653333646500000C010007312E302E302E3000004701001A2E4E45544672616D65776F726B2C56657273696F6E3D76342E300100540E144672616D65776F726B446973706C61794E616D65102E4E4554204672616D65776F726B20340A010005444542554700001901000C4765744C6973744974656D73077265646973716C000080F3010004005455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A446174614163636573730000000054020F497344657465726D696E697374696300540E1146696C6C526F774D6574686F644E616D65164765744C6973744974656D735F526F7746696C6C6572540E0F5461626C65446566696E6974696F6E1356616C7565206E76617263686172286D617829200100134765744C6973744974656D734174496E646578077265646973716C000080A2010002005455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A446174614163636573730000000054020F497344657465726D696E6973746963001801000B4C6973744C656674506F70077265646973716C00001901000C4C6973745269676874506F70077265646973716C000016010009416464546F4C697374077265646973716C00001A01000D4765744C6973744C656E677468077265646973716C00002201001553746F72655175657279526573756C747344617461077265646973716C00001B01000E536574537472696E6756616C7565077265646973716C000026010019536574537472696E6756616C756549664E6F74457869737473077265646973716C00001E010011476574536574537472696E6756616C7565077265646973716C00001B01000E476574537472696E6756616C7565077265646973716C00001801000B49734B6579457869737473077265646973716C00001701000A4765744B657954797065077265646973716C00001601000952656E616D654B6579077265646973716C00002201001553657452656C617469766545787069726174696F6E077265646973716C00001F010012536574457861637445787069726174696F6E077265646973716C0000160100094765744B657954544C077265646973716C00001601000944656C6574654B6579077265646973716C0000140100074765744B657973077265646973716C000080F0010004005455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A446174614163636573730000000054020F497344657465726D696E697374696300540E1146696C6C526F774D6574686F644E616D65114765744B6579735F526F7746696C6C6572540E0F5461626C65446566696E6974696F6E154B65794E616D65206E7661726368617228353132291A01000D476574536572766572496E666F077265646973716C00008105010004005455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A446174614163636573730000000054020F497344657465726D696E697374696300540E1146696C6C526F774D6574686F644E616D6511476574496E666F5F526F7746696C6C6572540E0F5461626C65446566696E6974696F6E2A4B65794E616D65206E7661726368617228353132292C2056616C7565206E76617263686172286D6178291801000B536176654368616E676573077265646973716C000012010005466C757368077265646973716C00001901000C4765744C6173745361766564077265646973716C0000090100044974656D0000190100010054510C44656661756C7456616C75650E04363337396F0100010054510C44656661756C7456616C7565505A53797374656D2E44424E756C6C2C206D73636F726C69622C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D62373761356335363139333465303839180100010054510C44656661756C7456616C75650800000000180100010054510C44656661756C7456616C756508FFFFFFFF150100010054510C44656661756C7456616C75650201150100010054510C44656661756C7456616C75650200160100010054510C44656661756C7456616C75650E012A00000000000000C1A34456000000000200000057000000108C0000106E0000525344534FBA35F2B2B0214FB24683367CCDFA5001000000633A5C50726F6A656374735C5265646953514C43616368655C526564697353716C43616368655C6F626A5C52656C656173655C5265646953716C2E706462008F8C00000000000000000000A98C00000020000000000000000000000000000000000000000000009B8C0000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C000000000000FF2500200010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000001800008000000000000000000000000000000100010000003000008000000000000000000000000000000100000000004800000058A000000C03000000000000000000000C0334000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE00000100000001000000000000000100000000003F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B0046C020000010053007400720069006E006700460069006C00650049006E0066006F0000004802000001003000300030003000300034006200300000001A000100010043006F006D006D0065006E007400730000000000000022000100010043006F006D00700061006E0079004E0061006D0065000000000000000000380008000100460069006C0065004400650073006300720069007000740069006F006E00000000005200650064006900530071006C000000300008000100460069006C006500560065007200730069006F006E000000000031002E0030002E0030002E003000000038000C00010049006E007400650072006E0061006C004E0061006D00650000005200650064006900530071006C002E0064006C006C0000004800120001004C006500670061006C0043006F007000790072006900670068007400000043006F0070007900720069006700680074002000A90020002000320030003100350000002A00010001004C006500670061006C00540072006100640065006D00610072006B007300000000000000000040000C0001004F0072006900670069006E0061006C00460069006C0065006E0061006D00650000005200650064006900530071006C002E0064006C006C000000300008000100500072006F0064007500630074004E0061006D006500000000005200650064006900530071006C000000340008000100500072006F006400750063007400560065007200730069006F006E00000031002E0030002E0030002E003000000038000800010041007300730065006D0062006C0079002000560065007200730069006F006E00000031002E0030002E0030002E0030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000C000000BC3C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 26 | WITH PERMISSION_SET = UNSAFE 27 | 28 | 29 | GO 30 | CREATE PROCEDURE redisql.AddToList(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000), @value nvarchar(4000), @addToEnd bit=0, @expiration time=null) 31 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlLists].[AddToList] 32 | GO 33 | 34 | 35 | GO 36 | CREATE FUNCTION redisql.DeleteKey(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000)) 37 | RETURNS bit 38 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlKeysManipulationFunctions].[DeleteKey] 39 | GO 40 | 41 | 42 | GO 43 | CREATE PROCEDURE redisql.Flush(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null) 44 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlGlobalServerFunctions].[Flush] 45 | GO 46 | 47 | 48 | GO 49 | CREATE FUNCTION redisql.GetServerInfo(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null) 50 | RETURNS table(KeyName nvarchar(512), Value nvarchar(max)) 51 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlGlobalServerFunctions].[GetInfo] 52 | GO 53 | 54 | 55 | GO 56 | CREATE FUNCTION redisql.GetKeys(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @filter nvarchar(4000)='*') 57 | RETURNS table(KeyName nvarchar(512)) 58 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlKeysManipulationFunctions].[GetKeys] 59 | GO 60 | 61 | 62 | GO 63 | CREATE FUNCTION redisql.GetKeyTTL(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000)) 64 | RETURNS int 65 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlKeysManipulationFunctions].[GetKeyTTL] 66 | GO 67 | 68 | 69 | GO 70 | CREATE FUNCTION redisql.GetKeyType(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000)) 71 | RETURNS nvarchar(4000) 72 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlKeysManipulationFunctions].[GetKeyType] 73 | GO 74 | 75 | 76 | GO 77 | CREATE FUNCTION redisql.GetLastSaved(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null) 78 | RETURNS datetime2 79 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlGlobalServerFunctions].[GetLastSaved] 80 | GO 81 | 82 | 83 | GO 84 | CREATE FUNCTION redisql.GetListItemsAtIndex(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000), @index int) 85 | RETURNS nvarchar(4000) 86 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlLists].[GetListItemAtIndex] 87 | GO 88 | 89 | 90 | GO 91 | CREATE FUNCTION redisql.GetListItems(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000), @start int=0, @end int=-1) 92 | RETURNS table(Value nvarchar(max)) 93 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlLists].[GetListItems] 94 | GO 95 | 96 | 97 | GO 98 | CREATE FUNCTION redisql.GetListLength(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000)) 99 | RETURNS int 100 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlLists].[GetListLength] 101 | GO 102 | 103 | 104 | GO 105 | CREATE FUNCTION redisql.GetSetStringValue(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000), @value nvarchar(4000), @expiration time=null) 106 | RETURNS nvarchar(4000) 107 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlStringValuesFunctions].[GetSetStringValue] 108 | GO 109 | 110 | 111 | GO 112 | CREATE FUNCTION redisql.GetStringValue(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000)) 113 | RETURNS nvarchar(4000) 114 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlStringValuesFunctions].[GetStringValue] 115 | GO 116 | 117 | 118 | GO 119 | CREATE FUNCTION redisql.IsKeyExists(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000)) 120 | RETURNS bit 121 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlKeysManipulationFunctions].[IsKeyExists] 122 | GO 123 | 124 | 125 | GO 126 | CREATE FUNCTION redisql.ListLeftPop(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000)) 127 | RETURNS nvarchar(4000) 128 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlLists].[LeftPop] 129 | GO 130 | 131 | 132 | GO 133 | CREATE FUNCTION redisql.RenameKey(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000), @keyNewName nvarchar(4000)) 134 | RETURNS bit 135 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlKeysManipulationFunctions].[Rename] 136 | GO 137 | 138 | 139 | GO 140 | CREATE FUNCTION redisql.ListRightPop(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000)) 141 | RETURNS nvarchar(4000) 142 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlLists].[RightPop] 143 | GO 144 | 145 | 146 | GO 147 | CREATE PROCEDURE redisql.SaveChanges(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @isBackground bit=0) 148 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlGlobalServerFunctions].[Save] 149 | GO 150 | 151 | 152 | GO 153 | CREATE FUNCTION redisql.SetExactExpiration(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000), @expiration datetime2) 154 | RETURNS bit 155 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlKeysManipulationFunctions].[SetExactExpiration] 156 | GO 157 | 158 | 159 | GO 160 | CREATE FUNCTION redisql.SetRelativeExpiration(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000), @expiration time) 161 | RETURNS bit 162 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlKeysManipulationFunctions].[SetRelativeExpiration] 163 | GO 164 | 165 | 166 | GO 167 | CREATE PROCEDURE redisql.SetStringValue(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000), @value nvarchar(4000), @expiration time=null) 168 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlStringValuesFunctions].[SetStringValue] 169 | GO 170 | 171 | 172 | GO 173 | CREATE FUNCTION redisql.SetStringValueIfNotExists(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000), @value nvarchar(4000), @expiration time=null) 174 | RETURNS bit 175 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlStringValuesFunctions].[SetStringValueIfNotExists] 176 | GO 177 | 178 | 179 | GO 180 | CREATE PROCEDURE redisql.StoreQueryResultsData(@host nvarchar(4000), @port int=6379, @password nvarchar(4000)=null, @dbId int=null, @key nvarchar(4000), @query nvarchar(4000), @expiration time=null, @replaceExisting bit=1) 181 | AS EXTERNAL NAME[RediSql].[RediSql.SqlClrComponents.RedisqlRowsets].[StoreQueryResultsData] 182 | GO 183 | 184 | 185 | GO 186 | 187 | SET ANSI_NULLS ON 188 | GO 189 | SET QUOTED_IDENTIFIER ON 190 | GO 191 | 192 | CREATE PROCEDURE redisql.GetStoredRowset 193 | @host nvarchar(250), @port int = 6379, @password nvarchar(100) = null, @dbId int = null, @key nvarchar(256) 194 | AS 195 | 196 | BEGIN 197 | SET NOCOUNT ON; 198 | 199 | IF OBJECT_ID('tempdb..#items') IS NOT NULL DROP TABLE #items 200 | 201 | CREATE TABLE #items(val nvarchar(max)) 202 | INSERT INTO #items(val) 203 | SELECT Value 204 | FROM redisql.GetListItems(@host, @port, @password, @dbId, @key, default, default) 205 | 206 | IF (SELECT COUNT(*) FROM #items) = 0 207 | BEGIN 208 | SELECT NULL 209 | RETURN -1 210 | END 211 | 212 | DELETE TOP (1) 213 | FROM #items 214 | 215 | DECLARE @metadataXml xml = (SELECT TOP 1 cast(val as xml) FROM #items) 216 | DELETE TOP (1) 217 | FROM #items 218 | 219 | DECLARE @columnsMetadata table(Seq int, Name nvarchar(250), DataType varchar(100)) 220 | INSERT INTO @columnsMetadata(Seq, Name, DataType) 221 | SELECT col.value('(@order)[1]', 'nvarchar(max)'), 222 | col.value('(@name)[1]', 'nvarchar(max)'), 223 | col.value('(@sqlType)[1]', 'nvarchar(max)') 224 | FROM @metadataXml.nodes('/ColumnsMetadata/Column') as columns(col) 225 | 226 | DECLARE @dynamicSelectors nvarchar(max) 227 | SELECT @dynamicSelectors =COALESCE(@dynamicSelectors + ', ', '') + 'T.C.value(''/item[1]/I' +CAST(Seq as varchar(10)) +'[1]'', ''' + DataType + ''') ' + Name 228 | FROM @columnsMetadata 229 | ORDER BY Seq 230 | 231 | DECLARE @sql nvarchar(max) = 232 | ' 233 | SELECT o.* 234 | FROM #items 235 | OUTER APPLY ( 236 | SELECT CAST(val as xml) xmlData 237 | ) rowXml 238 | OUTER APPLY ( 239 | SELECT TOP 1 dataColumns.* 240 | FROM rowXml.xmlData.nodes(''/item/*'') as T(C) 241 | OUTER APPLY ( 242 | SELECT ' + @dynamicSelectors + ' 243 | ) dataColumns 244 | ) o 245 | ' 246 | EXECUTE(@sql) 247 | RETURN (SELECT COUNT(*) FROM #items) 248 | END 249 | 250 | GO 251 | GO 252 | 253 | CREATE PROCEDURE [redisql].[ConvertXmlToRowset] 254 | ( 255 | @input xml 256 | ) 257 | AS 258 | BEGIN 259 | IF OBJECT_ID('tempdb..#dataToPivot') IS NOT NULL DROP TABLE #dataToPivot 260 | 261 | CREATE TABLE #dataToPivot (BatchID uniqueidentifier, KeyName nvarchar(max), Value nvarchar(max)) 262 | INSERT INTO #dataToPivot(BatchID, KeyName, Value) 263 | 264 | SELECT rowXml.ID, 265 | keyValueSet.Name, 266 | keyValueSet.Value 267 | FROM @input.nodes('/items/item') T(c) 268 | OUTER APPLY ( 269 | SELECT CAST(T.c.query('.') as xml) xmlData, 270 | NEWID() id 271 | ) rowXml 272 | OUTER APPLY ( 273 | SELECT 274 | C.Name, 275 | C.Value 276 | FROM rowXml.xmlData.nodes('/item/*') as T(C) 277 | OUTER APPLY ( 278 | SELECT 279 | T.C.value('local-name(.)', 'nvarchar(max)') as Name, 280 | T.C.value('(./text())[1]', 'nvarchar(max)') as Value 281 | UNION ALL 282 | SELECT 283 | A.C.value('local-name(.)', 'nvarchar(max)') as Name, 284 | A.C.value('.', 'nvarchar(max)') as Value 285 | FROM T.C.nodes('@*') as A(C) 286 | ) as C 287 | where C.Value is not null 288 | ) keyValueSet 289 | 290 | DECLARE @colsNames NVARCHAR(2000) 291 | SELECT @colsNames =COALESCE(@colsNames + ', ', '') + '[' +KeyName + ']' 292 | FROM #dataToPivot 293 | GROUP BY KeyName 294 | DECLARE @query NVARCHAR(4000) 295 | 296 | SET @query = N' SELECT '+ 297 | @colsNames +' 298 | FROM 299 | ( 300 | SELECT t2.BatchID 301 | ,t1.KeyName 302 | ,t1.Value 303 | FROM #dataToPivot AS t1 304 | JOIN #dataToPivot AS t2 ON t1.BatchID = t2.BatchID 305 | ) p 306 | PIVOT ( 307 | MAX([Value]) 308 | FOR KeyName IN ( '+@colsNames +' ) 309 | ) AS pvt 310 | ORDER BY BatchID;' 311 | EXECUTE(@query) 312 | 313 | END 314 | 315 | 316 | GO 317 | 318 | SET ANSI_NULLS ON 319 | GO 320 | SET QUOTED_IDENTIFIER ON 321 | GO 322 | CREATE PROCEDURE redisql.GetSetStoredRowset 323 | @key nvarchar(250), 324 | @host nvarchar(50), 325 | @port int = 6379, 326 | @password nvarchar(50) = null, 327 | @dbId int = null, 328 | @expiration time = null, 329 | @query nvarchar(max) 330 | AS 331 | BEGIN 332 | SET NOCOUNT ON; 333 | 334 | IF (redisql.GetKeyType(@host, @port, @password, @dbId, @key) = 'Rowset') 335 | BEGIN 336 | IF (@expiration IS NOT NULL) 337 | BEGIN 338 | SELECT redisql.SetRelativeExpiration(@host, @port, @password, @dbId, @key, @expiration) 339 | END 340 | DECLARE @numberOfRows int 341 | EXECUTE @numberOfRows = redisql.GetStoredRowset @host, @port, @password, @dbId, @key 342 | RETURN @numberOfRows 343 | END 344 | ELSE 345 | BEGIN 346 | EXECUTE redisql.StoreQueryResultsData @host, @port, @password, @dbId, @key, @query, @expiration 347 | EXEC sp_executesql @query 348 | RETURN -1 349 | END 350 | END 351 | GO 352 | 353 | 354 | sp_configure 'show advanced options', 1; 355 | GO 356 | RECONFIGURE; 357 | GO 358 | sp_configure 'clr enabled', 1; 359 | GO 360 | RECONFIGURE; 361 | GO 362 | -------------------------------------------------------------------------------- /RedisSqlCache/Deployment/LICENSE.txt: -------------------------------------------------------------------------------- 1 | RediSql provided under MIT license. 2 | --------------------------------------- 3 | 4 | Copyright (c) 2015 Shahar Gvirtz 5 | 6 | 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | THE SOFTWARE. 29 | 30 | -------------------------------------------------------------------------------- /RedisSqlCache/Deployment/Readme.txt: -------------------------------------------------------------------------------- 1 | --------------------------------- 2 | RediSql - T-SQL client for Redis 3 | --------------------------------- 4 | 5 | README 6 | 7 | * RediSql provided as-is, with no guaranees at all. It's your responsibility to take all the necessary precautions before installing it. 8 | * RediSql installation is fairly simple: 9 | 1. Copy all text from install.sql to text editor (SQL Server Management Studio recommended) 10 | 2. Change the first line - replace "check1" with your DB name 11 | 3. Make sure you run the script on the DB you want it, either by using sqlcmd and using the "-d" flag, or by choosing the DB name from 12 | the combo box in SSMS 13 | 4. Execute the statements. 14 | 15 | * How the installation script is going to affect your DB? 16 | - New schema, called "redisql" will created in your DB with the same permissions as the dbo schema 17 | - 2 SQL CLR assemblies will be added to your database 18 | - SQL CLR will be enabled in the server 19 | - Multiple functions and stored procedures will be added, all under "redisql" schema 20 | - (for a full list please refer to the official site, http://redisql.ishahar.net ) 21 | 22 | * Where can you get more information? 23 | - Official website: http://redisql.ishahar.net 24 | - GitHub (for the source code): http://github.com/shahargv/redisql 25 | 26 | Hope you'll enjoy RediSql :) 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /RedisSqlCache/Deployment/Uninstall.sql: -------------------------------------------------------------------------------- 1 | --RediSql - Redis client for T-SQL 2 | --For installation instructions and other information, please visit http://redisql.ishahar.net 3 | 4 | --REMEMBER: make sure you run this query on the correct database! 5 | DROP PROCEDURE redisql.AddToList 6 | DROP FUNCTION redisql.DeleteKey 7 | DROP PROCEDURE redisql.Flush 8 | DROP FUNCTION redisql.GetServerInfo 9 | DROP FUNCTION redisql.GetKeys 10 | DROP FUNCTION redisql.GetKeyTTL 11 | DROP FUNCTION redisql.GetKeyType 12 | DROP FUNCTION redisql.GetLastSaved 13 | DROP FUNCTION redisql.GetListItemsAtIndex 14 | DROP FUNCTION redisql.GetListItems 15 | DROP FUNCTION redisql.GetListLength 16 | DROP FUNCTION redisql.GetSetStringValue 17 | DROP FUNCTION redisql.GetStringValue 18 | DROP FUNCTION redisql.IsKeyExists 19 | DROP FUNCTION redisql.ListLeftPop 20 | DROP FUNCTION redisql.RenameKey 21 | DROP FUNCTION redisql.ListRightPop 22 | DROP PROCEDURE redisql.SaveChanges 23 | DROP FUNCTION redisql.SetExactExpiration 24 | DROP FUNCTION redisql.SetRelativeExpiration 25 | DROP PROCEDURE redisql.SetStringValue 26 | DROP FUNCTION redisql.SetStringValueIfNotExists 27 | DROP PROCEDURE redisql.StoreQueryResultsData 28 | DROP ASSEMBLY [RediSql] 29 | 30 | GO 31 | DROP ASSEMBLY [SqlClrDeclarations] 32 | 33 | GO 34 | DROP PROCEDURE [redisql].[GetStoredRowset] 35 | GO 36 | DROP PROCEDURE [redisql].[ConvertXmlToRowset] 37 | GO 38 | DROP PROCEDURE [redisql].[GetSetStoredRowset] 39 | GO 40 | DROP SCHEMA [redisql] 41 | GO 42 | -------------------------------------------------------------------------------- /RedisSqlCache/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using SqlClrDeclarations.Attributes; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("RediSql")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("RediSql")] 14 | [assembly: AssemblyCopyright("Copyright © 2015")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | // The following GUID is for the ID of the typelib if this project is exposed to COM 25 | [assembly: Guid("666fe4b7-0a6b-44df-b179-c394234e33de")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | [assembly: AssemblyVersion("1.0.0.0")] 38 | [assembly: AssemblyFileVersion("1.0.0.0")] 39 | -------------------------------------------------------------------------------- /RedisSqlCache/RediSql.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {666FE4B7-0A6B-44DF-B179-C394234E33DE} 8 | Library 9 | Properties 10 | RediSql 11 | RediSql 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 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 | {56c24720-8053-4cf5-8bf8-bae7dba78424} 71 | SqlClrDeclarations 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | powershell $(ProjectDir)\Scripts\DeploymentScriptsGenerator.ps1 -InstallerTemplatePath $(ProjectDir)\Scripts\InstallerTemplate.txt -UninstallerTemplatePath $(ProjectDir)\Scripts\UninstallTemplate.txt -FinalInstallerScriptPath $(ProjectDir)\Deployment\Install.sql -FinalUninstallerScriptPath $(ProjectDir)\Deployment\Uninstall.sql -SolutionDir $(SolutionDir) -RedisqlBinDir $(TargetDir) -RedisqlProjDir $(ProjectDir) 80 | 81 | 88 | -------------------------------------------------------------------------------- /RedisSqlCache/RedisSharp/RedisSharp.cs: -------------------------------------------------------------------------------- 1 | // 2 | // redis-sharp.cs: ECMA CLI Binding to the Redis key-value storage system 3 | // 4 | // Authors: 5 | // Miguel de Icaza (miguel@gnome.org) 6 | // 7 | // Copyright 2010 Novell, Inc. 8 | // 9 | // Licensed under the same terms of reddis: new BSD license. 10 | // 11 | #define DEBUG 12 | 13 | using System; 14 | using System.IO; 15 | using System.Collections.Generic; 16 | using System.Net.Sockets; 17 | using System.Text; 18 | using System.Diagnostics; 19 | using System.Linq; 20 | 21 | 22 | public class Redis : IDisposable 23 | { 24 | Socket socket; 25 | BufferedStream bstream; 26 | 27 | public enum KeyType 28 | { 29 | None, String, List, Set, 30 | Hash, 31 | ZSet 32 | } 33 | 34 | public class ResponseException : Exception 35 | { 36 | public ResponseException(string code) : base("Response error") 37 | { 38 | Code = code; 39 | } 40 | 41 | public string Code { get; private set; } 42 | } 43 | 44 | public Redis(string host, int port) 45 | { 46 | if (host == null) 47 | throw new ArgumentNullException("host"); 48 | 49 | Host = host; 50 | Port = port; 51 | SendTimeout = -1; 52 | } 53 | 54 | public Redis(string host) : this(host, 6379) 55 | { 56 | } 57 | 58 | public Redis() : this("localhost", 6379) 59 | { 60 | } 61 | 62 | public string Host { get; private set; } 63 | public int Port { get; private set; } 64 | public int RetryTimeout { get; set; } 65 | public int RetryCount { get; set; } 66 | public int SendTimeout { get; set; } 67 | public string Password { get; set; } 68 | 69 | int db; 70 | public int Db 71 | { 72 | get 73 | { 74 | return db; 75 | } 76 | 77 | set 78 | { 79 | db = value; 80 | SendExpectSuccess("SELECT", db); 81 | } 82 | } 83 | 84 | public string this[string key] 85 | { 86 | get { return GetString(key); } 87 | set { Set(key, value); } 88 | } 89 | 90 | public void Set(string key, string value) 91 | { 92 | if (key == null) 93 | throw new ArgumentNullException("key"); 94 | if (value == null) 95 | throw new ArgumentNullException("value"); 96 | 97 | Set(key, Encoding.UTF8.GetBytes(value)); 98 | } 99 | 100 | public void Set(string key, byte[] value) 101 | { 102 | if (key == null) 103 | throw new ArgumentNullException("key"); 104 | if (value == null) 105 | throw new ArgumentNullException("value"); 106 | 107 | if (value.Length > 1073741824) 108 | throw new ArgumentException("value exceeds 1G", "value"); 109 | 110 | if (!SendDataCommand(value, "SET", key)) 111 | throw new Exception("Unable to connect"); 112 | ExpectSuccess(); 113 | } 114 | 115 | public bool SetNX(string key, string value) 116 | { 117 | if (key == null) 118 | throw new ArgumentNullException("key"); 119 | if (value == null) 120 | throw new ArgumentNullException("value"); 121 | 122 | return SetNX(key, Encoding.UTF8.GetBytes(value)); 123 | } 124 | 125 | public bool SetNX(string key, byte[] value) 126 | { 127 | if (key == null) 128 | throw new ArgumentNullException("key"); 129 | if (value == null) 130 | throw new ArgumentNullException("value"); 131 | 132 | if (value.Length > 1073741824) 133 | throw new ArgumentException("value exceeds 1G", "value"); 134 | 135 | return SendDataExpectInt(value, "SETNX", key) > 0 ? true : false; 136 | } 137 | 138 | public void Set(IDictionary dict) 139 | { 140 | if (dict == null) 141 | throw new ArgumentNullException("dict"); 142 | 143 | Set(dict.ToDictionary(k => k.Key, v => Encoding.UTF8.GetBytes(v.Value))); 144 | } 145 | 146 | public void Set(IDictionary dict) 147 | { 148 | if (dict == null) 149 | throw new ArgumentNullException("dict"); 150 | 151 | MSet(dict.Keys.ToArray(), dict.Values.ToArray()); 152 | } 153 | 154 | public void MSet(string[] keys, byte[][] values) 155 | { 156 | if (keys.Length != values.Length) 157 | throw new ArgumentException("keys and values must have the same size"); 158 | 159 | byte[] nl = Encoding.UTF8.GetBytes("\r\n"); 160 | MemoryStream ms = new MemoryStream(); 161 | 162 | for (int i = 0; i < keys.Length; i++) 163 | { 164 | byte[] key = Encoding.UTF8.GetBytes(keys[i]); 165 | byte[] val = values[i]; 166 | byte[] kLength = Encoding.UTF8.GetBytes("$" + key.Length + "\r\n"); 167 | byte[] k = Encoding.UTF8.GetBytes(keys[i] + "\r\n"); 168 | byte[] vLength = Encoding.UTF8.GetBytes("$" + val.Length + "\r\n"); 169 | ms.Write(kLength, 0, kLength.Length); 170 | ms.Write(k, 0, k.Length); 171 | ms.Write(vLength, 0, vLength.Length); 172 | ms.Write(val, 0, val.Length); 173 | ms.Write(nl, 0, nl.Length); 174 | } 175 | 176 | SendDataRESP(ms.ToArray(), "*" + (keys.Length * 2 + 1) + "\r\n$4\r\nMSET\r\n"); 177 | ExpectSuccess(); 178 | } 179 | 180 | public byte[] Get(string key) 181 | { 182 | if (key == null) 183 | throw new ArgumentNullException("key"); 184 | return SendExpectData("GET", key); 185 | } 186 | 187 | public string GetString(string key) 188 | { 189 | if (key == null) 190 | throw new ArgumentNullException("key"); 191 | var dataBytes = Get(key); 192 | if (dataBytes != null) 193 | return Encoding.UTF8.GetString(dataBytes); 194 | return null; 195 | } 196 | 197 | public byte[][] Sort(SortOptions options) 198 | { 199 | return Sort(options.Key, options.StoreInKey, options.ToArgs()); 200 | } 201 | 202 | public byte[][] Sort(string key, string destination, params object[] options) 203 | { 204 | if (key == null) 205 | throw new ArgumentNullException("key"); 206 | 207 | int offset = string.IsNullOrEmpty(destination) ? 1 : 3; 208 | object[] args = new object[offset + options.Length]; 209 | 210 | args[0] = key; 211 | Array.Copy(options, 0, args, offset, options.Length); 212 | if (offset == 1) 213 | { 214 | return SendExpectDataArray("SORT", args); 215 | } 216 | else 217 | { 218 | args[1] = "STORE"; 219 | args[2] = destination; 220 | int n = SendExpectInt("SORT", args); 221 | return new byte[n][]; 222 | } 223 | } 224 | 225 | public byte[] GetSet(string key, byte[] value) 226 | { 227 | if (key == null) 228 | throw new ArgumentNullException("key"); 229 | if (value == null) 230 | throw new ArgumentNullException("value"); 231 | 232 | if (value.Length > 1073741824) 233 | throw new ArgumentException("value exceeds 1G", "value"); 234 | 235 | if (!SendDataCommand(value, "GETSET", key)) 236 | throw new Exception("Unable to connect"); 237 | 238 | return ReadData(); 239 | } 240 | 241 | public string GetSet(string key, string value) 242 | { 243 | if (key == null) 244 | throw new ArgumentNullException("key"); 245 | if (value == null) 246 | throw new ArgumentNullException("value"); 247 | var previousValue = GetSet(key, Encoding.UTF8.GetBytes(value)); 248 | if (previousValue != null) 249 | return Encoding.UTF8.GetString(previousValue); 250 | return null; 251 | 252 | } 253 | 254 | string ReadLine() 255 | { 256 | StringBuilder sb = new StringBuilder(); 257 | int c; 258 | 259 | while ((c = bstream.ReadByte()) != -1) 260 | { 261 | if (c == '\r') 262 | continue; 263 | if (c == '\n') 264 | break; 265 | sb.Append((char)c); 266 | } 267 | return sb.ToString(); 268 | } 269 | 270 | void Connect() 271 | { 272 | socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 273 | socket.NoDelay = true; 274 | socket.SendTimeout = SendTimeout; 275 | socket.Connect(Host, Port); 276 | if (!socket.Connected) 277 | { 278 | socket.Close(); 279 | socket = null; 280 | return; 281 | } 282 | bstream = new BufferedStream(new NetworkStream(socket), 16 * 1024); 283 | 284 | if (Password != null) 285 | SendExpectSuccess("AUTH", Password); 286 | } 287 | 288 | byte[] end_data = new byte[] { (byte)'\r', (byte)'\n' }; 289 | 290 | bool SendDataCommand(byte[] data, string cmd, params object[] args) 291 | { 292 | string resp = "*" + (1 + args.Length + 1).ToString() + "\r\n"; 293 | resp += "$" + cmd.Length + "\r\n" + cmd + "\r\n"; 294 | foreach (object arg in args) 295 | { 296 | string argStr = arg.ToString(); 297 | int argStrLength = Encoding.UTF8.GetByteCount(argStr); 298 | resp += "$" + argStrLength + "\r\n" + argStr + "\r\n"; 299 | } 300 | resp += "$" + data.Length + "\r\n"; 301 | 302 | return SendDataRESP(data, resp); 303 | } 304 | 305 | bool SendDataRESP(byte[] data, string resp) 306 | { 307 | if (socket == null) 308 | Connect(); 309 | if (socket == null) 310 | return false; 311 | 312 | byte[] r = Encoding.UTF8.GetBytes(resp); 313 | try 314 | { 315 | Log("C", resp); 316 | socket.Send(r); 317 | if (data != null) 318 | { 319 | socket.Send(data); 320 | socket.Send(end_data); 321 | } 322 | } 323 | catch (SocketException) 324 | { 325 | // timeout; 326 | socket.Close(); 327 | socket = null; 328 | 329 | return false; 330 | } 331 | return true; 332 | } 333 | 334 | bool SendCommand(string cmd, params object[] args) 335 | { 336 | if (socket == null) 337 | Connect(); 338 | if (socket == null) 339 | return false; 340 | 341 | string resp = "*" + (1 + args.Length).ToString() + "\r\n"; 342 | resp += "$" + cmd.Length + "\r\n" + cmd + "\r\n"; 343 | foreach (object arg in args) 344 | { 345 | string argStr = arg.ToString(); 346 | int argStrLength = Encoding.UTF8.GetByteCount(argStr); 347 | resp += "$" + argStrLength + "\r\n" + argStr + "\r\n"; 348 | } 349 | 350 | byte[] r = Encoding.UTF8.GetBytes(resp); 351 | try 352 | { 353 | Log("C", resp); 354 | socket.Send(r); 355 | } 356 | catch (SocketException) 357 | { 358 | // timeout; 359 | socket.Close(); 360 | socket = null; 361 | 362 | return false; 363 | } 364 | return true; 365 | } 366 | 367 | [Conditional("DEBUG")] 368 | void Log(string id, string message) 369 | { 370 | Console.WriteLine(id + ": " + message.Trim().Replace("\r\n", " ")); 371 | } 372 | 373 | void ExpectSuccess() 374 | { 375 | int c = bstream.ReadByte(); 376 | if (c == -1) 377 | throw new ResponseException("No more data"); 378 | 379 | string s = ReadLine(); 380 | Log("S", (char)c + s); 381 | if (c == '-') 382 | throw new ResponseException(s.StartsWith("ERR ") ? s.Substring(4) : s); 383 | } 384 | 385 | void SendExpectSuccess(string cmd, params object[] args) 386 | { 387 | if (!SendCommand(cmd, args)) 388 | throw new Exception("Unable to connect"); 389 | 390 | ExpectSuccess(); 391 | } 392 | 393 | int SendDataExpectInt(byte[] data, string cmd, params object[] args) 394 | { 395 | if (!SendDataCommand(data, cmd, args)) 396 | throw new Exception("Unable to connect"); 397 | 398 | int c = bstream.ReadByte(); 399 | if (c == -1) 400 | throw new ResponseException("No more data"); 401 | 402 | string s = ReadLine(); 403 | Log("S", (char)c + s); 404 | if (c == '-') 405 | throw new ResponseException(s.StartsWith("ERR ") ? s.Substring(4) : s); 406 | if (c == ':') 407 | { 408 | int i; 409 | if (int.TryParse(s, out i)) 410 | return i; 411 | } 412 | throw new ResponseException("Unknown reply on integer request: " + c + s); 413 | } 414 | 415 | int SendExpectInt(string cmd, params object[] args) 416 | { 417 | if (!SendCommand(cmd, args)) 418 | throw new Exception("Unable to connect"); 419 | 420 | int c = bstream.ReadByte(); 421 | if (c == -1) 422 | throw new ResponseException("No more data"); 423 | 424 | string s = ReadLine(); 425 | Log("S", (char)c + s); 426 | if (c == '-') 427 | throw new ResponseException(s.StartsWith("ERR ") ? s.Substring(4) : s); 428 | if (c == ':') 429 | { 430 | int i; 431 | if (int.TryParse(s, out i)) 432 | return i; 433 | } 434 | throw new ResponseException("Unknown reply on integer request: " + c + s); 435 | } 436 | 437 | string SendExpectString(string cmd, params object[] args) 438 | { 439 | if (!SendCommand(cmd, args)) 440 | throw new Exception("Unable to connect"); 441 | 442 | int c = bstream.ReadByte(); 443 | if (c == -1) 444 | throw new ResponseException("No more data"); 445 | 446 | string s = ReadLine(); 447 | Log("S", (char)c + s); 448 | if (c == '-') 449 | throw new ResponseException(s.StartsWith("ERR ") ? s.Substring(4) : s); 450 | if (c == '+') 451 | return s; 452 | 453 | throw new ResponseException("Unknown reply on integer request: " + c + s); 454 | } 455 | 456 | // 457 | // This one does not throw errors 458 | // 459 | string SendGetString(string cmd, params object[] args) 460 | { 461 | if (!SendCommand(cmd, args)) 462 | throw new Exception("Unable to connect"); 463 | 464 | return ReadLine(); 465 | } 466 | 467 | byte[] SendExpectData(string cmd, params object[] args) 468 | { 469 | if (!SendCommand(cmd, args)) 470 | throw new Exception("Unable to connect"); 471 | 472 | return ReadData(); 473 | } 474 | 475 | byte[] ReadData() 476 | { 477 | string s = ReadLine(); 478 | Log("S", s); 479 | if (s.Length == 0) 480 | throw new ResponseException("Zero length respose"); 481 | 482 | char c = s[0]; 483 | if (c == '-') 484 | throw new ResponseException(s.StartsWith("-ERR ") ? s.Substring(5) : s.Substring(1)); 485 | 486 | if (c == '$') 487 | { 488 | if (s == "$-1") 489 | return null; 490 | int n; 491 | 492 | if (Int32.TryParse(s.Substring(1), out n)) 493 | { 494 | byte[] retbuf = new byte[n]; 495 | 496 | int bytesRead = 0; 497 | do 498 | { 499 | int read = bstream.Read(retbuf, bytesRead, n - bytesRead); 500 | if (read < 1) 501 | throw new ResponseException("Invalid termination mid stream"); 502 | bytesRead += read; 503 | } 504 | while (bytesRead < n); 505 | if (bstream.ReadByte() != '\r' || bstream.ReadByte() != '\n') 506 | throw new ResponseException("Invalid termination"); 507 | return retbuf; 508 | } 509 | throw new ResponseException("Invalid length"); 510 | } 511 | 512 | /* don't treat arrays here because only one element works -- use DataArray! 513 | //returns the number of matches 514 | if (c == '*') { 515 | int n; 516 | if (Int32.TryParse(s.Substring(1), out n)) 517 | return n <= 0 ? new byte [0] : ReadData(); 518 | 519 | throw new ResponseException ("Unexpected length parameter" + r); 520 | } 521 | */ 522 | 523 | throw new ResponseException("Unexpected reply: " + s); 524 | } 525 | 526 | public bool ContainsKey(string key) 527 | { 528 | if (key == null) 529 | throw new ArgumentNullException("key"); 530 | return SendExpectInt("EXISTS", key) == 1; 531 | } 532 | 533 | public bool Remove(string key) 534 | { 535 | if (key == null) 536 | throw new ArgumentNullException("key"); 537 | return SendExpectInt("DEL", key) == 1; 538 | } 539 | 540 | public int Remove(params string[] args) 541 | { 542 | if (args == null) 543 | throw new ArgumentNullException("args"); 544 | return SendExpectInt("DEL", args); 545 | } 546 | 547 | public int Increment(string key) 548 | { 549 | if (key == null) 550 | throw new ArgumentNullException("key"); 551 | return SendExpectInt("INCR", key); 552 | } 553 | 554 | public int Increment(string key, int count) 555 | { 556 | if (key == null) 557 | throw new ArgumentNullException("key"); 558 | return SendExpectInt("INCRBY", key, count); 559 | } 560 | 561 | public int Decrement(string key) 562 | { 563 | if (key == null) 564 | throw new ArgumentNullException("key"); 565 | return SendExpectInt("DECR", key); 566 | } 567 | 568 | public int Decrement(string key, int count) 569 | { 570 | if (key == null) 571 | throw new ArgumentNullException("key"); 572 | return SendExpectInt("DECRBY", key, count); 573 | } 574 | 575 | public KeyType TypeOf(string key) 576 | { 577 | if (key == null) 578 | throw new ArgumentNullException("key"); 579 | switch (SendExpectString("TYPE", key)) 580 | { 581 | case "none": 582 | return KeyType.None; 583 | case "string": 584 | return KeyType.String; 585 | case "set": 586 | return KeyType.Set; 587 | case "list": 588 | return KeyType.List; 589 | case "zset": 590 | return KeyType.ZSet; 591 | case "hash": 592 | return KeyType.Hash; 593 | } 594 | throw new ResponseException("Invalid value"); 595 | } 596 | 597 | public string RandomKey() 598 | { 599 | return SendExpectString("RANDOMKEY"); 600 | } 601 | 602 | public bool Rename(string oldKeyname, string newKeyname) 603 | { 604 | if (oldKeyname == null) 605 | throw new ArgumentNullException("oldKeyname"); 606 | if (newKeyname == null) 607 | throw new ArgumentNullException("newKeyname"); 608 | return SendGetString("RENAME", oldKeyname, newKeyname)[0] == '+'; 609 | } 610 | 611 | public bool Expire(string key, int seconds) 612 | { 613 | if (key == null) 614 | throw new ArgumentNullException("key"); 615 | return SendExpectInt("EXPIRE", key, seconds) == 1; 616 | } 617 | 618 | public bool ExpireAt(string key, int time) 619 | { 620 | if (key == null) 621 | throw new ArgumentNullException("key"); 622 | return SendExpectInt("EXPIREAT", key, time) == 1; 623 | } 624 | 625 | public int TimeToLive(string key) 626 | { 627 | if (key == null) 628 | throw new ArgumentNullException("key"); 629 | return SendExpectInt("TTL", key); 630 | } 631 | 632 | public int DbSize 633 | { 634 | get 635 | { 636 | return SendExpectInt("DBSIZE"); 637 | } 638 | } 639 | 640 | public void Save() 641 | { 642 | SendExpectSuccess("SAVE"); 643 | } 644 | 645 | public void BackgroundSave() 646 | { 647 | SendExpectSuccess("BGSAVE"); 648 | } 649 | 650 | public void Shutdown() 651 | { 652 | SendCommand("SHUTDOWN"); 653 | try 654 | { 655 | // the server may return an error 656 | string s = ReadLine(); 657 | Log("S", s); 658 | if (s.Length == 0) 659 | throw new ResponseException("Zero length respose"); 660 | throw new ResponseException(s.StartsWith("-ERR ") ? s.Substring(5) : s.Substring(1)); 661 | } 662 | catch (IOException) 663 | { 664 | // this is the expected good result 665 | socket.Close(); 666 | socket = null; 667 | } 668 | } 669 | 670 | public void FlushAll() 671 | { 672 | SendExpectSuccess("FLUSHALL"); 673 | } 674 | 675 | public void FlushDb() 676 | { 677 | SendExpectSuccess("FLUSHDB"); 678 | } 679 | 680 | const long UnixEpoch = 621355968000000000L; 681 | 682 | public DateTime LastSave 683 | { 684 | get 685 | { 686 | int t = SendExpectInt("LASTSAVE"); 687 | 688 | return new DateTime(UnixEpoch) + TimeSpan.FromSeconds(t); 689 | } 690 | } 691 | 692 | public Dictionary GetInfo() 693 | { 694 | byte[] r = SendExpectData("INFO"); 695 | var dict = new Dictionary(); 696 | 697 | foreach (var line in Encoding.UTF8.GetString(r).Split('\n')) 698 | { 699 | int p = line.IndexOf(':'); 700 | if (p == -1) 701 | continue; 702 | dict.Add(line.Substring(0, p), line.Substring(p + 1)); 703 | } 704 | return dict; 705 | } 706 | 707 | public string[] Keys 708 | { 709 | get 710 | { 711 | return GetKeys("*"); 712 | } 713 | } 714 | 715 | public string[] GetKeys(string pattern) 716 | { 717 | if (pattern == null) 718 | throw new ArgumentNullException("pattern"); 719 | 720 | return SendExpectStringArray("KEYS", pattern); 721 | } 722 | 723 | public byte[][] MGet(params string[] keys) 724 | { 725 | if (keys == null) 726 | throw new ArgumentNullException("keys"); 727 | if (keys.Length == 0) 728 | throw new ArgumentException("keys"); 729 | 730 | return SendExpectDataArray("MGET", keys); 731 | } 732 | 733 | 734 | public string[] SendExpectStringArray(string cmd, params object[] args) 735 | { 736 | byte[][] reply = SendExpectDataArray(cmd, args); 737 | string[] keys = new string[reply.Length]; 738 | for (int i = 0; i < reply.Length; i++) 739 | keys[i] = Encoding.UTF8.GetString(reply[i]); 740 | return keys; 741 | } 742 | 743 | public byte[][] SendExpectDataArray(string cmd, params object[] args) 744 | { 745 | if (!SendCommand(cmd, args)) 746 | throw new Exception("Unable to connect"); 747 | int c = bstream.ReadByte(); 748 | if (c == -1) 749 | throw new ResponseException("No more data"); 750 | 751 | string s = ReadLine(); 752 | Log("S", (char)c + s); 753 | if (c == '-') 754 | throw new ResponseException(s.StartsWith("ERR ") ? s.Substring(4) : s); 755 | if (c == '*') 756 | { 757 | int count; 758 | if (int.TryParse(s, out count)) 759 | { 760 | byte[][] result = new byte[count][]; 761 | 762 | for (int i = 0; i < count; i++) 763 | result[i] = ReadData(); 764 | 765 | return result; 766 | } 767 | } 768 | throw new ResponseException("Unknown reply on multi-request: " + c + s); 769 | } 770 | 771 | #region List commands 772 | public byte[][] ListRange(string key, int start, int end) 773 | { 774 | return SendExpectDataArray("LRANGE", key, start, end); 775 | } 776 | 777 | public void LeftPush(string key, string value) 778 | { 779 | LeftPush(key, Encoding.UTF8.GetBytes(value)); 780 | } 781 | 782 | public void LeftPush(string key, byte[] value) 783 | { 784 | SendDataCommand(value, "LPUSH", key); 785 | ExpectSuccess(); 786 | } 787 | 788 | public void RightPush(string key, string value) 789 | { 790 | RightPush(key, Encoding.UTF8.GetBytes(value)); 791 | } 792 | 793 | public void RightPush(string key, byte[] value) 794 | { 795 | SendDataCommand(value, "RPUSH", key); 796 | ExpectSuccess(); 797 | } 798 | 799 | public int ListLength(string key) 800 | { 801 | return SendExpectInt("LLEN", key); 802 | } 803 | 804 | public byte[] ListIndex(string key, int index) 805 | { 806 | SendCommand("LINDEX", key, index); 807 | return ReadData(); 808 | } 809 | 810 | public byte[] LeftPop(string key) 811 | { 812 | SendCommand("LPOP", key); 813 | return ReadData(); 814 | } 815 | 816 | public byte[] RightPop(string key) 817 | { 818 | SendCommand("RPOP", key); 819 | return ReadData(); 820 | } 821 | #endregion 822 | 823 | #region Set commands 824 | public bool AddToSet(string key, byte[] member) 825 | { 826 | return SendDataExpectInt(member, "SADD", key) > 0; 827 | } 828 | 829 | public bool AddToSet(string key, string member) 830 | { 831 | return AddToSet(key, Encoding.UTF8.GetBytes(member)); 832 | } 833 | 834 | public int CardinalityOfSet(string key) 835 | { 836 | return SendExpectInt("SCARD", key); 837 | } 838 | 839 | public bool IsMemberOfSet(string key, byte[] member) 840 | { 841 | return SendDataExpectInt(member, "SISMEMBER", key) > 0; 842 | } 843 | 844 | public bool IsMemberOfSet(string key, string member) 845 | { 846 | return IsMemberOfSet(key, Encoding.UTF8.GetBytes(member)); 847 | } 848 | 849 | public byte[][] GetMembersOfSet(string key) 850 | { 851 | return SendExpectDataArray("SMEMBERS", key); 852 | } 853 | 854 | public byte[] GetRandomMemberOfSet(string key) 855 | { 856 | return SendExpectData("SRANDMEMBER", key); 857 | } 858 | 859 | public byte[] PopRandomMemberOfSet(string key) 860 | { 861 | return SendExpectData("SPOP", key); 862 | } 863 | 864 | public bool RemoveFromSet(string key, byte[] member) 865 | { 866 | return SendDataExpectInt(member, "SREM", key) > 0; 867 | } 868 | 869 | public bool RemoveFromSet(string key, string member) 870 | { 871 | return RemoveFromSet(key, Encoding.UTF8.GetBytes(member)); 872 | } 873 | 874 | public byte[][] GetUnionOfSets(params string[] keys) 875 | { 876 | if (keys == null) 877 | throw new ArgumentNullException(); 878 | 879 | return SendExpectDataArray("SUNION", keys); 880 | 881 | } 882 | 883 | void StoreSetCommands(string cmd, params string[] keys) 884 | { 885 | if (String.IsNullOrEmpty(cmd)) 886 | throw new ArgumentNullException("cmd"); 887 | 888 | if (keys == null) 889 | throw new ArgumentNullException("keys"); 890 | 891 | SendExpectSuccess(cmd, keys); 892 | } 893 | 894 | public void StoreUnionOfSets(params string[] keys) 895 | { 896 | StoreSetCommands("SUNIONSTORE", keys); 897 | } 898 | 899 | public byte[][] GetIntersectionOfSets(params string[] keys) 900 | { 901 | if (keys == null) 902 | throw new ArgumentNullException(); 903 | 904 | return SendExpectDataArray("SINTER", keys); 905 | } 906 | 907 | public void StoreIntersectionOfSets(params string[] keys) 908 | { 909 | StoreSetCommands("SINTERSTORE", keys); 910 | } 911 | 912 | public byte[][] GetDifferenceOfSets(params string[] keys) 913 | { 914 | if (keys == null) 915 | throw new ArgumentNullException(); 916 | 917 | return SendExpectDataArray("SDIFF", keys); 918 | } 919 | 920 | public void StoreDifferenceOfSets(params string[] keys) 921 | { 922 | StoreSetCommands("SDIFFSTORE", keys); 923 | } 924 | 925 | public bool MoveMemberToSet(string srcKey, string destKey, byte[] member) 926 | { 927 | return SendDataExpectInt(member, "SMOVE", srcKey, destKey) > 0; 928 | } 929 | #endregion 930 | 931 | public void Dispose() 932 | { 933 | Dispose(true); 934 | GC.SuppressFinalize(this); 935 | } 936 | 937 | ~Redis() 938 | { 939 | Dispose(false); 940 | } 941 | 942 | protected virtual void Dispose(bool disposing) 943 | { 944 | if (disposing) 945 | { 946 | SendCommand("QUIT"); 947 | ExpectSuccess(); 948 | socket.Close(); 949 | socket = null; 950 | } 951 | } 952 | } 953 | 954 | public class SortOptions 955 | { 956 | public string Key { get; set; } 957 | public bool Descending { get; set; } 958 | public bool Lexographically { get; set; } 959 | public Int32 LowerLimit { get; set; } 960 | public Int32 UpperLimit { get; set; } 961 | public string By { get; set; } 962 | public string StoreInKey { get; set; } 963 | public string Get { get; set; } 964 | 965 | public object[] ToArgs() 966 | { 967 | System.Collections.ArrayList args = new System.Collections.ArrayList(); 968 | 969 | if (LowerLimit != 0 || UpperLimit != 0) 970 | { 971 | args.Add("LIMIT"); 972 | args.Add(LowerLimit); 973 | args.Add(UpperLimit); 974 | } 975 | if (Lexographically) 976 | args.Add("ALPHA"); 977 | if (!string.IsNullOrEmpty(By)) 978 | { 979 | args.Add("BY"); 980 | args.Add(By); 981 | } 982 | if (!string.IsNullOrEmpty(Get)) 983 | { 984 | args.Add("GET"); 985 | args.Add(Get); 986 | } 987 | return args.ToArray(); 988 | } 989 | } 990 | -------------------------------------------------------------------------------- /RedisSqlCache/Scripts/DeploymentScriptsGenerator.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [string]$InstallerTemplatePath, 3 | [string]$UninstallerTemplatePath, 4 | [string]$FinalInstallerScriptPath, 5 | [string]$FinalUninstallerScriptPath, 6 | [string]$SolutionDir, 7 | [string]$RedisqlBinDir, 8 | [string]$RedisqlProjDir 9 | ) 10 | function ZipFiles( $zipfilename, $sourcedir ) 11 | { 12 | Add-Type -Assembly System.IO.Compression.FileSystem 13 | $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal 14 | [System.IO.Compression.ZipFile]::CreateFromDirectory($sourcedir, 15 | $zipfilename, $compressionLevel, $false) 16 | } 17 | 18 | $sqlScriptsGeneratorPath = [IO.Path]::Combine($SolutionDir, "ScriptGenerator","InstallerScriptGenerator.exe") 19 | Write-Host $sqlScriptsGeneratorPath 20 | $installerTemplateText = [IO.File]::ReadAllText($InstallerTemplatePath) 21 | $tmpInstallerFile = [IO.Path]::GetTempFileName() 22 | [IO.File]::WriteAllText($tmpInstallerFile, $installerTemplateText.Replace("!!!binDir!!!", $RedisqlBinDir).Replace("!!!projDir!!!", $RedisqlProjDir)) 23 | write-host $tmpInstallerFile 24 | Start-Process -FilePath $sqlScriptsGeneratorPath -ArgumentList "$tmpInstallerFile $FinalInstallerScriptPath" -Wait 25 | 26 | $uninstallerTemplateText = [IO.File]::ReadAllText($UninstallerTemplatePath) 27 | $tmpUninstallerFile = [IO.Path]::GetTempFileName() 28 | [IO.File]::WriteAllText($tmpUninstallerFile, $uninstallerTemplateText.Replace("!!!binDir!!!", $RedisqlBinDir).Replace("!!!projDir!!!", $RedisqlProjDir)) 29 | write-host $tmpUninstallerFile 30 | Start-Process -FilePath $sqlScriptsGeneratorPath -ArgumentList "$tmpUninstallerFile $FinalUninstallerScriptPath" -Wait -------------------------------------------------------------------------------- /RedisSqlCache/Scripts/InstallerTemplate.txt: -------------------------------------------------------------------------------- 1 | --RediSql - Redis client for T-SQL 2 | --For installation instructions and other information, please visit http://redisql.ishahar.net 3 | 4 | --REMEMBER: make sure you run this query on the correct database! 5 | 6 | DECLARE @dbName nvarchar(50) = '[check1]' --CHANGE HERE TO YOUR DB NAME 7 | 8 | EXEC('ALTER DATABASE ' + @dbname + ' SET TRUSTWORTHY ON') 9 | 10 | 11 | GO 12 | CREATE SCHEMA [redisql] AUTHORIZATION [dbo] 13 | GO 14 | ~~~InstallScript:~~~!!!binDir!!!\SqlClrDeclarations.dll 15 | GO 16 | ~~~InstallScript:~~~!!!binDir!!!\RediSql.dll 17 | GO 18 | ~~~IncludeFile:~~~!!!projDir!!!\TSQLCode\GetStoredRowset.sql 19 | GO 20 | ~~~IncludeFile:~~~!!!projDir!!!\TSQLCode\XmlToRowset.sql 21 | GO 22 | ~~~IncludeFile:~~~!!!projDir!!!\TSQLCode\GetSetStoredRowset.sql 23 | 24 | sp_configure 'show advanced options', 1; 25 | GO 26 | RECONFIGURE; 27 | GO 28 | sp_configure 'clr enabled', 1; 29 | GO 30 | RECONFIGURE; 31 | GO -------------------------------------------------------------------------------- /RedisSqlCache/Scripts/SanityTest.sql: -------------------------------------------------------------------------------- 1 | --TEST 1 : non existent key test 2 | DECLARE @nonExistentKeyExists bit = [redisql].[IsKeyExists] ( 3 | 'localhost' 4 | ,6379 5 | ,default 6 | ,default 7 | ,CAST(NEWID() as varchar(50)) 8 | ) 9 | IF @nonExistentKeyExists = 1 10 | BEGIN 11 | PRINT 'ERROR: non existent key test' 12 | END 13 | ELSE 14 | BEGIN 15 | PRINT 'success: non existent key test' 16 | END 17 | GO 18 | 19 | --TEST 2: add and remove key 20 | DECLARE @test2KeyName varchar(50) = CAST(NEWID() as varchar(50)) 21 | EXEC [redisql].[SetStringValue] 22 | @host = N'localhost', 23 | @port = 6379, 24 | @key = @test2KeyName, 25 | @value = N'gv' 26 | IF (SELECT [redisql].[IsKeyExists] ('localhost',default,default,default,@test2KeyName)) = 0 27 | BEGIN 28 | PRINT 'ERROR (test 2):add key and check if exists' 29 | END 30 | ELSE 31 | BEGIN 32 | PRINT 'success: test 2 - key added successfully' 33 | END 34 | 35 | EXEC [redisql].DeleteKey 36 | @host='localhost', 37 | @key=@test2KeyName 38 | IF (SELECT [redisql].[IsKeyExists] ('localhost',default,default,default,@test2KeyName)) = 0 39 | BEGIN 40 | PRINT 'success (test 2): key removed successfully' 41 | END 42 | ELSE 43 | BEGIN 44 | PRINT 'ERROR: test 2 - key exists after removing' 45 | END 46 | GO 47 | --TEST 3: add key with expiration 48 | DECLARE @test3KeyName varchar(50) = CAST(NEWID() as varchar(50)) 49 | EXEC [redisql].[SetStringValue] 50 | @host = N'localhost', 51 | @port = 6379, 52 | @key = @test3KeyName, 53 | @value = N'gv', 54 | @expiration = '00:00:10' 55 | IF (SELECT [redisql].[IsKeyExists] ('localhost',default,default,default,@test3KeyName)) = 0 56 | BEGIN 57 | PRINT 'ERROR:add key with expiration (test 3) - key not exists after adding it' 58 | END 59 | WAITFOR DELAY '00:00:11' 60 | IF (SELECT [redisql].[IsKeyExists] ('localhost',default,default,default,@test3KeyName)) = 1 61 | BEGIN 62 | PRINT 'ERROR:add key with expiration (test 3) - key exists after expiration time' 63 | END 64 | ELSE 65 | BEGIN 66 | PRINT 'success: add key and check if exists with expiration (test 3)' 67 | END 68 | GO 69 | --TEST 4: Check lists 70 | DECLARE @test4KeyName varchar(50) = CAST(NEWID() as varchar(50)) 71 | EXEC [redisql].AddToList 72 | @host = N'localhost', 73 | @port = 6379, 74 | @key = @test4KeyName, 75 | @value = N'val1' 76 | EXEC [redisql].AddToList 77 | @host = N'localhost', 78 | @port = 6379, 79 | @key = @test4KeyName, 80 | @value = N'val2' 81 | EXEC [redisql].AddToList 82 | @host = N'localhost', 83 | @port = 6379, 84 | @key = @test4KeyName, 85 | @value = N'val3' 86 | DECLARE @numberOfItemsInResults int = (SELECT COUNT(*) FROM redisql.GetListItems('localhost', default, default, default, @test4KeyName, default, default)) 87 | IF @numberOfItemsInResults <> 3 88 | BEGIN 89 | PRINT 'ERROR: lists test (test 4)' 90 | END 91 | ELSE 92 | BEGIN 93 | PRINT 'success: lists test (test 4)' 94 | END 95 | --TEST 5: Rowset storing 96 | DECLARE @test5KeyName varchar(50) = CAST(NEWID() as varchar(50)) 97 | 98 | IF OBJECT_ID('tempdb..#test5') IS NOT NULL DROP TABLE #test5 99 | CREATE TABLE #test5(col1 nvarchar(200), col2 varchar(200), col3 nvarchar(max) null, col4 int null) 100 | INSERT INTO #test5(col1, col2, col3, col4) VALUES ('c1val', 'c2val', 'c3val', 9) 101 | INSERT INTO #test5(col1, col2, col3, col4) VALUES ('c1val', 'c2val', null, 90) 102 | INSERT INTO #test5(col1, col2, col3, col4) VALUES ('c1val', 'c2val', 'c3val', 91) 103 | INSERT INTO #test5(col1, col2, col3, col4) VALUES ('c1val', 'c2val', 'c3val', null) 104 | INSERT INTO #test5(col1, col2, col3, col4) VALUES ('c1val', 'c2val', 'c3val', null) 105 | EXEC [redisql].StoreQueryResultsData 106 | @host = N'localhost', 107 | @port = 6379, 108 | @key = @test5KeyName, 109 | @query = N'SELECT * FROM #test5', 110 | @replaceExisting = 1 111 | DECLARE @backFromCache table (col1 nvarchar(200), col2 varchar(200), col3 nvarchar(max) null, col4 int null) 112 | IF OBJECT_ID('tempdb..#test5_b') IS NOT NULL DROP TABLE #test5_b 113 | CREATE TABLE #test5_b(col1 nvarchar(200), col2 varchar(200), col3 nvarchar(max) null, col4 int null) 114 | INSERT INTO #test5_b(col1,col2,col3,col4) EXEC [redisql].[GetStoredRowset] @host = N'localhost', @key =@test5KeyName 115 | IF(SELECT COUNT(*) FROM #test5_b) <> 5 116 | BEGIN 117 | PRINT 'ERROR: rowset test - incorrect number of total returned rows (test5)' 118 | END 119 | ELSE 120 | BEGIN 121 | PRINT 'success: rowset test - correct number of total returned rows (test5)' 122 | END 123 | IF(SELECT COUNT(*) FROM #test5_b WHERE col4 IS NULL) <> 2 124 | BEGIN 125 | PRINT 'ERROR: rowset test - incorrect number of null returned rows (test5)' 126 | END 127 | ELSE 128 | BEGIN 129 | PRINT 'success: rowset test - correct number of null returned rows (test5)' 130 | END -------------------------------------------------------------------------------- /RedisSqlCache/Scripts/UninstallTemplate.txt: -------------------------------------------------------------------------------- 1 | --RediSql - Redis client for T-SQL 2 | --For installation instructions and other information, please visit http://redisql.ishahar.net 3 | 4 | --REMEMBER: make sure you run this query on the correct database! 5 | ~~~UninstallScript:~~~!!!binDir!!!\RediSql.dll 6 | GO 7 | ~~~UninstallScript:~~~!!!binDir!!!\SqlClrDeclarations.dll 8 | GO 9 | DROP PROCEDURE [redisql].[GetStoredRowset] 10 | GO 11 | DROP PROCEDURE [redisql].[ConvertXmlToRowset] 12 | GO 13 | DROP PROCEDURE [redisql].[GetSetStoredRowset] 14 | GO 15 | DROP SCHEMA [redisql] 16 | GO 17 | -------------------------------------------------------------------------------- /RedisSqlCache/Scripts/Usage.sql: -------------------------------------------------------------------------------- 1 | SELECT [redisql].[IsKeyExists] ( 2 | 'localhost' 3 | ,6379 4 | ,default 5 | ,default 6 | ,'check1' 7 | ) 8 | 9 | GO 10 | 11 | EXEC [redisql].[SetStringValue] 12 | @host = N'localhost', 13 | @port = 6379, 14 | @key = N'check1', 15 | @value = N'gv' 16 | 17 | 18 | GO 19 | 20 | SELECT [redisql].[GetStringValue] ( 21 | 'localhost' 22 | ,6379 23 | ,default 24 | ,default 25 | ,'check1') 26 | 27 | GO -------------------------------------------------------------------------------- /RedisSqlCache/SqlClrComponents/Common/RedisConnection.cs: -------------------------------------------------------------------------------- 1 | namespace RediSql.SqlClrComponents.Common 2 | { 3 | internal static class RedisConnection 4 | { 5 | internal static Redis GetConnection(string host, int port, string password = null, int? dbId = null) 6 | { 7 | Redis redis = new Redis(host, port); 8 | if (password != null) 9 | redis.Password = password; 10 | if (dbId != null) 11 | redis.Db = dbId.Value; 12 | return redis; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /RedisSqlCache/SqlClrComponents/Enums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace RediSql.SqlClrComponents 7 | { 8 | public enum KeyType 9 | { 10 | NotExisting, 11 | String, 12 | List, 13 | Rowset, 14 | Set, 15 | Hash 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /RedisSqlCache/SqlClrComponents/RedisqlGlobalServerFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Data.SqlTypes; 5 | using Microsoft.SqlServer.Server; 6 | using RediSql.SqlClrComponents.Common; 7 | using SqlClrDeclarations.Attributes; 8 | 9 | namespace RediSql.SqlClrComponents 10 | { 11 | public static class RedisqlGlobalServerFunctions 12 | { 13 | [SqlInstallerScriptGeneratorExportedFunction("GetServerInfo", "redisql")] 14 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false, FillRowMethodName = "GetInfo_RowFiller", TableDefinition = "KeyName nvarchar(512), Value nvarchar(max)")] 15 | public static IEnumerable GetInfo(string host, 16 | [SqlParameter(DefaultValue = "6379")]int port, 17 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 18 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId) 19 | { 20 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 21 | { 22 | return redis.GetInfo(); 23 | } 24 | } 25 | 26 | public static void GetInfo_RowFiller(object item, out SqlString title, out SqlString value) 27 | { 28 | var settingRow = (KeyValuePair)item; 29 | title = settingRow.Key; 30 | value = settingRow.Value; 31 | } 32 | 33 | [SqlInstallerScriptGeneratorExportedProcedure("SaveChanges", "redisql")] 34 | [SqlProcedure] 35 | public static void Save(string host, 36 | [SqlParameter(DefaultValue = "6379")]int port, 37 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 38 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 39 | [SqlParameter(DefaultValue = true)] bool isBackground) 40 | 41 | { 42 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 43 | { 44 | if (isBackground) 45 | { 46 | redis.BackgroundSave(); 47 | } 48 | else 49 | { 50 | redis.Save(); 51 | } 52 | } 53 | } 54 | 55 | [SqlInstallerScriptGeneratorExportedProcedure("Flush", "redisql")] 56 | [SqlProcedure] 57 | public static void Flush(string host, 58 | [SqlParameter(DefaultValue = "6379")]int port, 59 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 60 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId) 61 | 62 | { 63 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 64 | { 65 | if (dbId != null) 66 | { 67 | redis.FlushDb(); 68 | } 69 | else 70 | { 71 | redis.FlushAll(); 72 | } 73 | } 74 | } 75 | 76 | [SqlInstallerScriptGeneratorExportedFunction("GetLastSaved", "redisql")] 77 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 78 | public static DateTime GetLastSaved(string host, 79 | [SqlParameter(DefaultValue = "6379")]int port, 80 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 81 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId) 82 | { 83 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 84 | { 85 | return redis.LastSave; 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /RedisSqlCache/SqlClrComponents/RedisqlKeysManipulationFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Data.SqlTypes; 4 | using Microsoft.SqlServer.Server; 5 | using RediSql.Common; 6 | using RediSql.SqlClrComponents.Common; 7 | using SqlClrDeclarations.Attributes; 8 | 9 | namespace RediSql.SqlClrComponents 10 | { 11 | public static class RedisqlKeysManipulationFunctions 12 | { 13 | [SqlInstallerScriptGeneratorExportedFunction("IsKeyExists", "redisql")] 14 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 15 | public static bool IsKeyExists(string host, 16 | [SqlParameter(DefaultValue = "6379")]int port, 17 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 18 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 19 | string key) 20 | { 21 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 22 | { 23 | return redis.ContainsKey(key); 24 | } 25 | } 26 | 27 | [SqlInstallerScriptGeneratorExportedFunction("GetKeyType", "redisql")] 28 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 29 | public static string GetKeyType(string host, 30 | [SqlParameter(DefaultValue = "6379")]int port, 31 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 32 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 33 | string key) 34 | { 35 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 36 | { 37 | var redisKeyType = redis.TypeOf(key); 38 | switch (redisKeyType) 39 | { 40 | case Redis.KeyType.None: 41 | return KeyType.NotExisting.ToString(); 42 | case Redis.KeyType.String: 43 | return KeyType.String.ToString(); 44 | case Redis.KeyType.List: 45 | if (RedisqlLists.GetListItemAtIndex(host, port, password, dbId, key, 0).Equals(RedisqlRowsets.RowsetMagic, StringComparison.OrdinalIgnoreCase)) 46 | return KeyType.Rowset.ToString(); 47 | return KeyType.List.ToString(); 48 | case Redis.KeyType.Set: 49 | return KeyType.Set.ToString(); 50 | case Redis.KeyType.ZSet: 51 | return KeyType.Set.ToString(); 52 | case Redis.KeyType.Hash: 53 | return KeyType.Hash.ToString(); 54 | default: 55 | throw new ArgumentOutOfRangeException(); 56 | } 57 | } 58 | } 59 | 60 | [SqlInstallerScriptGeneratorExportedFunction("RenameKey", "redisql")] 61 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 62 | public static bool Rename(string host, 63 | [SqlParameter(DefaultValue = "6379")]int port, 64 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 65 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 66 | string key, 67 | string keyNewName) 68 | { 69 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 70 | { 71 | return redis.Rename(key, keyNewName); 72 | } 73 | } 74 | 75 | [SqlInstallerScriptGeneratorExportedFunction("SetRelativeExpiration", "redisql")] 76 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 77 | public static bool SetRelativeExpiration(string host, 78 | [SqlParameter(DefaultValue = "6379")]int port, 79 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 80 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 81 | string key, 82 | TimeSpan expiration) 83 | { 84 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 85 | { 86 | return redis.Expire(key, (int)expiration.TotalSeconds); 87 | } 88 | } 89 | 90 | [SqlInstallerScriptGeneratorExportedFunction("SetExactExpiration", "redisql")] 91 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 92 | public static bool SetExactExpiration(string host, 93 | [SqlParameter(DefaultValue = "6379")]int port, 94 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 95 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 96 | string key, 97 | DateTime expiration) 98 | { 99 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 100 | { 101 | return redis.ExpireAt(key, (int)DateTimeUtils.ToUnixTime(expiration)); 102 | } 103 | } 104 | 105 | [SqlInstallerScriptGeneratorExportedFunction("GetKeyTTL", "redisql")] 106 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 107 | public static int? GetKeyTTL(string host, 108 | [SqlParameter(DefaultValue = "6379")]int port, 109 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 110 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 111 | string key) 112 | { 113 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 114 | { 115 | var ttl = redis.TimeToLive(key); 116 | return ttl >= 0 ? ttl : (int?)null; 117 | } 118 | } 119 | 120 | [SqlInstallerScriptGeneratorExportedFunction("DeleteKey", "redisql")] 121 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 122 | public static bool DeleteKey(string host, 123 | [SqlParameter(DefaultValue = "6379")]int port, 124 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 125 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 126 | string key) 127 | { 128 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 129 | { 130 | return redis.Remove(key); 131 | } 132 | } 133 | 134 | [SqlInstallerScriptGeneratorExportedFunction("GetKeys", "redisql")] 135 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false, FillRowMethodName = "GetKeys_RowFiller", TableDefinition = "KeyName nvarchar(512)")] 136 | public static IEnumerable GetKeys(string host, 137 | [SqlParameter(DefaultValue = "6379")]int port, 138 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 139 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 140 | [SqlParameter(DefaultValue = "*")]string filter) 141 | { 142 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 143 | { 144 | return redis.GetKeys(filter); 145 | } 146 | } 147 | 148 | public static void GetKeys_RowFiller(object item, out SqlString keyName) 149 | { 150 | keyName = (string)item; 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /RedisSqlCache/SqlClrComponents/RedisqlLists.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Data.SqlTypes; 5 | using System.Linq; 6 | using System.Text; 7 | using Microsoft.SqlServer.Server; 8 | using RediSql.SqlClrComponents.Common; 9 | using SqlClrDeclarations.Attributes; 10 | 11 | namespace RediSql.SqlClrComponents 12 | { 13 | public static class RedisqlLists 14 | { 15 | [SqlInstallerScriptGeneratorExportedFunction("GetListItems", "redisql")] 16 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false, FillRowMethodName = "GetListItems_RowFiller", TableDefinition = "Value nvarchar(max)")] 17 | public static IEnumerable GetListItems(string host, 18 | [SqlParameter(DefaultValue = "6379")]int port, 19 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 20 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 21 | string key, 22 | [SqlParameter(DefaultValue = 0)]int start, 23 | [SqlParameter(DefaultValue = -1)]int end) 24 | { 25 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 26 | { 27 | return redis.ListRange(key, start, end); 28 | } 29 | } 30 | 31 | public static void GetListItems_RowFiller(object item, out SqlString value) 32 | { 33 | byte[] txtEncoded = (byte[])item; 34 | value = Encoding.UTF8.GetString(txtEncoded); 35 | } 36 | 37 | [SqlInstallerScriptGeneratorExportedFunction("GetListItemsAtIndex", "redisql")] 38 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 39 | public static string GetListItemAtIndex(string host, 40 | [SqlParameter(DefaultValue = "6379")]int port, 41 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 42 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 43 | string key, 44 | int index) 45 | { 46 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 47 | { 48 | return Encoding.UTF8.GetString(redis.ListIndex(key, index)); 49 | } 50 | } 51 | 52 | [SqlInstallerScriptGeneratorExportedFunction("ListLeftPop", "redisql")] 53 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 54 | public static string LeftPop(string host, 55 | [SqlParameter(DefaultValue = "6379")]int port, 56 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 57 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 58 | string key) 59 | { 60 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 61 | { 62 | return Encoding.UTF8.GetString(redis.LeftPop(key)); 63 | } 64 | } 65 | 66 | [SqlInstallerScriptGeneratorExportedFunction("ListRightPop", "redisql")] 67 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 68 | public static string RightPop(string host, 69 | [SqlParameter(DefaultValue = "6379")]int port, 70 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 71 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 72 | string key) 73 | { 74 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 75 | { 76 | return Encoding.UTF8.GetString(redis.RightPop(key)); 77 | } 78 | } 79 | 80 | [SqlInstallerScriptGeneratorExportedProcedure("AddToList", "redisql")] 81 | [SqlProcedure] 82 | public static void AddToList(string host, 83 | [SqlParameter(DefaultValue = "6379")]int port, 84 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 85 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 86 | string key, 87 | string value, 88 | [SqlParameter(DefaultValue = true)]bool addToEnd, 89 | [SqlParameter(DefaultValue = typeof(DBNull))] TimeSpan? expiration) 90 | { 91 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 92 | { 93 | if (addToEnd) 94 | { 95 | redis.RightPush(key, value); 96 | } 97 | else 98 | { 99 | redis.LeftPush(key, value); 100 | } 101 | if (expiration != null) 102 | { 103 | redis.Expire(key, (int)expiration.Value.TotalSeconds); 104 | } 105 | } 106 | } 107 | 108 | [SqlInstallerScriptGeneratorExportedFunction("GetListLength", "redisql")] 109 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 110 | public static int GetListLength(string host, 111 | [SqlParameter(DefaultValue = "6379")]int port, 112 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 113 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 114 | string key) 115 | { 116 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 117 | { 118 | return redis.ListLength(key); 119 | } 120 | } 121 | 122 | 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /RedisSqlCache/SqlClrComponents/RedisqlRowsets.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Data.SqlClient; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Xml; 9 | using System.Xml.Linq; 10 | using Microsoft.SqlServer.Server; 11 | using RediSql.SqlClrComponents.Common; 12 | using SqlClrDeclarations.Attributes; 13 | 14 | namespace RediSql.SqlClrComponents 15 | { 16 | public static class RedisqlRowsets 17 | { 18 | [SqlInstallerScriptGeneratorExportedProcedure("StoreQueryResultsData", "redisql")] 19 | [SqlProcedure] 20 | public static void StoreQueryResultsData(string host, 21 | [SqlParameter(DefaultValue = "6379")]int port, 22 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 23 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 24 | string key, 25 | string query, 26 | [SqlParameter(DefaultValue = typeof(DBNull))]TimeSpan? expiration, 27 | [SqlParameter(DefaultValue = false)]bool replaceExisting) 28 | { 29 | var rowsXmls = ExecuteQueryAndGetResultList(query); 30 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 31 | { 32 | if (redis.ContainsKey(key)) 33 | { 34 | if (replaceExisting) 35 | { 36 | redis.Remove(key); 37 | } 38 | else 39 | { 40 | throw new Exception("key with the same name already exists, and replace flag not enabled"); 41 | } 42 | } 43 | List valuesToAdd = new List(rowsXmls.Count + 1) { RowsetMagic }; 44 | valuesToAdd.AddRange(rowsXmls); 45 | valuesToAdd.ForEach(val => RedisqlLists.AddToList(host, port, password, dbId, key, val, true, null)); 46 | if (expiration != null) 47 | { 48 | redis.Expire(key, (int)expiration.Value.TotalSeconds); 49 | } 50 | } 51 | } 52 | 53 | private static List ExecuteQueryAndGetResultList(string query) 54 | { 55 | List valuesToAdd = new List(); 56 | using (SqlConnection connection = new SqlConnection("context connection=true")) 57 | { 58 | connection.Open(); 59 | valuesToAdd.Add(GetColumnMetadataXml(connection, query)); 60 | using (SqlCommand queryCommand = new SqlCommand(query, connection)) 61 | using (SqlDataReader rowsetReader = queryCommand.ExecuteReader()) 62 | { 63 | while (rowsetReader.Read()) 64 | { 65 | XElement el = new XElement("item"); 66 | for (int index = 0; index < rowsetReader.FieldCount; index++) 67 | { 68 | if (!rowsetReader.IsDBNull(index)) 69 | el.Add(new XElement("I" + (index + 1), rowsetReader.GetValue(index))); 70 | } 71 | valuesToAdd.Add(el.ToString()); 72 | } 73 | } 74 | } 75 | return valuesToAdd; 76 | } 77 | 78 | private static string GetColumnMetadataXml(SqlConnection connection, string query) 79 | { 80 | using (var cmd = new SqlCommand("sp_describe_first_result_set", connection)) 81 | { 82 | cmd.CommandType = CommandType.StoredProcedure; 83 | cmd.Parameters.AddWithValue("tsql", query); 84 | XElement el = new XElement("ColumnsMetadata"); 85 | using (var reader = cmd.ExecuteReader()) 86 | { 87 | while (reader.Read()) 88 | { 89 | el.Add(new XElement("Column", 90 | new XAttribute("order", reader["column_ordinal"]), 91 | new XAttribute("name", reader["name"]), 92 | new XAttribute("sqlType", reader["system_type_name"]))); 93 | } 94 | } 95 | return el.ToString(); 96 | } 97 | } 98 | 99 | public static string RowsetMagic => "REDISQLROWSET"; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /RedisSqlCache/SqlClrComponents/RedisqlStringValuesFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.SqlServer.Server; 3 | using RediSql.SqlClrComponents.Common; 4 | using SqlClrDeclarations.Attributes; 5 | 6 | namespace RediSql.SqlClrComponents 7 | { 8 | public static class RedisqlStringValuesFunctions 9 | { 10 | [SqlInstallerScriptGeneratorExportedProcedure("SetStringValue", "redisql")] 11 | [SqlProcedure] 12 | public static void SetStringValue(string host, 13 | [SqlParameter(DefaultValue = "6379")]int port, 14 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 15 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 16 | string key, 17 | string value, 18 | [SqlParameter(DefaultValue = typeof(DBNull))]TimeSpan? expiration) 19 | { 20 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 21 | { 22 | redis.Set(key, value); 23 | if (expiration != null) 24 | redis.Expire(key, (int)expiration.Value.TotalSeconds); 25 | } 26 | } 27 | 28 | [SqlInstallerScriptGeneratorExportedFunction("SetStringValueIfNotExists", "redisql")] 29 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 30 | public static bool SetStringValueIfNotExists(string host, 31 | [SqlParameter(DefaultValue = "6379")]int port, 32 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 33 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 34 | string key, 35 | string value, 36 | [SqlParameter(DefaultValue = typeof(DBNull))]TimeSpan? expiration) 37 | { 38 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 39 | { 40 | bool wasKeyCreated = redis.SetNX(key, value); 41 | if (wasKeyCreated && expiration != null) 42 | return redis.Expire(key, (int)expiration.Value.TotalSeconds); 43 | return wasKeyCreated; 44 | } 45 | } 46 | 47 | [SqlInstallerScriptGeneratorExportedFunction("GetSetStringValue", "redisql")] 48 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 49 | public static string GetSetStringValue(string host, 50 | [SqlParameter(DefaultValue = "6379")]int port, 51 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 52 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 53 | string key, 54 | string value, 55 | [SqlParameter(DefaultValue = typeof(DBNull))]TimeSpan? expiration) 56 | { 57 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 58 | { 59 | string result = redis.GetSet(key, value); 60 | if (expiration != null) 61 | redis.Expire(key, (int)expiration.Value.TotalSeconds); 62 | return result ?? value; //change the default Redis behavior, and make it be like GetSet on the rowset 63 | } 64 | } 65 | 66 | [SqlInstallerScriptGeneratorExportedFunction("GetStringValue", "redisql")] 67 | [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = false)] 68 | public static string GetStringValue(string host, 69 | [SqlParameter(DefaultValue = "6379")]int port, 70 | [SqlParameter(DefaultValue = typeof(DBNull))]string password, 71 | [SqlParameter(DefaultValue = typeof(DBNull))]int? dbId, 72 | string key) 73 | { 74 | using (var redis = RedisConnection.GetConnection(host, port, password, dbId)) 75 | { 76 | return redis.GetString(key); 77 | } 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /RedisSqlCache/TSQLCode/GetSetStoredRowset.sql: -------------------------------------------------------------------------------- 1 |  2 | SET ANSI_NULLS ON 3 | GO 4 | SET QUOTED_IDENTIFIER ON 5 | GO 6 | CREATE PROCEDURE redisql.GetSetStoredRowset 7 | @key nvarchar(250), 8 | @host nvarchar(50), 9 | @port int = 6379, 10 | @password nvarchar(50) = null, 11 | @dbId int = null, 12 | @expiration time = null, 13 | @query nvarchar(max) 14 | AS 15 | BEGIN 16 | SET NOCOUNT ON; 17 | 18 | IF (redisql.GetKeyType(@host, @port, @password, @dbId, @key) = 'Rowset') 19 | BEGIN 20 | IF (@expiration IS NOT NULL) 21 | BEGIN 22 | SELECT redisql.SetRelativeExpiration(@host, @port, @password, @dbId, @key, @expiration) 23 | END 24 | DECLARE @numberOfRows int 25 | EXECUTE @numberOfRows = redisql.GetStoredRowset @host, @port, @password, @dbId, @key 26 | RETURN @numberOfRows 27 | END 28 | ELSE 29 | BEGIN 30 | EXECUTE redisql.StoreQueryResultsData @host, @port, @password, @dbId, @key, @query, @expiration 31 | EXEC sp_executesql @query 32 | RETURN -1 33 | END 34 | END 35 | GO 36 | -------------------------------------------------------------------------------- /RedisSqlCache/TSQLCode/GetStoredRowset.sql: -------------------------------------------------------------------------------- 1 |  2 | SET ANSI_NULLS ON 3 | GO 4 | SET QUOTED_IDENTIFIER ON 5 | GO 6 | 7 | CREATE PROCEDURE redisql.GetStoredRowset 8 | @host nvarchar(250), @port int = 6379, @password nvarchar(100) = null, @dbId int = null, @key nvarchar(256) 9 | AS 10 | 11 | BEGIN 12 | SET NOCOUNT ON; 13 | 14 | IF OBJECT_ID('tempdb..#items') IS NOT NULL DROP TABLE #items 15 | 16 | CREATE TABLE #items(val nvarchar(max)) 17 | INSERT INTO #items(val) 18 | SELECT Value 19 | FROM redisql.GetListItems(@host, @port, @password, @dbId, @key, default, default) 20 | 21 | IF (SELECT COUNT(*) FROM #items) = 0 22 | BEGIN 23 | SELECT NULL 24 | RETURN -1 25 | END 26 | 27 | DELETE TOP (1) 28 | FROM #items 29 | 30 | DECLARE @metadataXml xml = (SELECT TOP 1 cast(val as xml) FROM #items) 31 | DELETE TOP (1) 32 | FROM #items 33 | 34 | DECLARE @columnsMetadata table(Seq int, Name nvarchar(250), DataType varchar(100)) 35 | INSERT INTO @columnsMetadata(Seq, Name, DataType) 36 | SELECT col.value('(@order)[1]', 'nvarchar(max)'), 37 | col.value('(@name)[1]', 'nvarchar(max)'), 38 | col.value('(@sqlType)[1]', 'nvarchar(max)') 39 | FROM @metadataXml.nodes('/ColumnsMetadata/Column') as columns(col) 40 | 41 | DECLARE @dynamicSelectors nvarchar(max) 42 | SELECT @dynamicSelectors =COALESCE(@dynamicSelectors + ', ', '') + 'T.C.value(''/item[1]/I' +CAST(Seq as varchar(10)) +'[1]'', ''' + DataType + ''') ' + Name 43 | FROM @columnsMetadata 44 | ORDER BY Seq 45 | 46 | DECLARE @sql nvarchar(max) = 47 | ' 48 | SELECT o.* 49 | FROM #items 50 | OUTER APPLY ( 51 | SELECT CAST(val as xml) xmlData 52 | ) rowXml 53 | OUTER APPLY ( 54 | SELECT TOP 1 dataColumns.* 55 | FROM rowXml.xmlData.nodes(''/item/*'') as T(C) 56 | OUTER APPLY ( 57 | SELECT ' + @dynamicSelectors + ' 58 | ) dataColumns 59 | ) o 60 | ' 61 | EXECUTE(@sql) 62 | RETURN (SELECT COUNT(*) FROM #items) 63 | END 64 | 65 | GO -------------------------------------------------------------------------------- /RedisSqlCache/TSQLCode/XmlToRowset.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE [redisql].[ConvertXmlToRowset] 3 | ( 4 | @input xml 5 | ) 6 | AS 7 | BEGIN 8 | IF OBJECT_ID('tempdb..#dataToPivot') IS NOT NULL DROP TABLE #dataToPivot 9 | 10 | CREATE TABLE #dataToPivot (BatchID uniqueidentifier, KeyName nvarchar(max), Value nvarchar(max)) 11 | INSERT INTO #dataToPivot(BatchID, KeyName, Value) 12 | 13 | SELECT rowXml.ID, 14 | keyValueSet.Name, 15 | keyValueSet.Value 16 | FROM @input.nodes('/items/item') T(c) 17 | OUTER APPLY ( 18 | SELECT CAST(T.c.query('.') as xml) xmlData, 19 | NEWID() id 20 | ) rowXml 21 | OUTER APPLY ( 22 | SELECT 23 | C.Name, 24 | C.Value 25 | FROM rowXml.xmlData.nodes('/item/*') as T(C) 26 | OUTER APPLY ( 27 | SELECT 28 | T.C.value('local-name(.)', 'nvarchar(max)') as Name, 29 | T.C.value('(./text())[1]', 'nvarchar(max)') as Value 30 | UNION ALL 31 | SELECT 32 | A.C.value('local-name(.)', 'nvarchar(max)') as Name, 33 | A.C.value('.', 'nvarchar(max)') as Value 34 | FROM T.C.nodes('@*') as A(C) 35 | ) as C 36 | where C.Value is not null 37 | ) keyValueSet 38 | 39 | DECLARE @colsNames NVARCHAR(2000) 40 | SELECT @colsNames =COALESCE(@colsNames + ', ', '') + '[' +KeyName + ']' 41 | FROM #dataToPivot 42 | GROUP BY KeyName 43 | DECLARE @query NVARCHAR(4000) 44 | 45 | SET @query = N' SELECT '+ 46 | @colsNames +' 47 | FROM 48 | ( 49 | SELECT t2.BatchID 50 | ,t1.KeyName 51 | ,t1.Value 52 | FROM #dataToPivot AS t1 53 | JOIN #dataToPivot AS t2 ON t1.BatchID = t2.BatchID 54 | ) p 55 | PIVOT ( 56 | MAX([Value]) 57 | FOR KeyName IN ( '+@colsNames +' ) 58 | ) AS pvt 59 | ORDER BY BatchID;' 60 | EXECUTE(@query) 61 | 62 | END 63 | 64 | -------------------------------------------------------------------------------- /ScriptGenerator/InstallerScriptGenerator.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahargv/redisql/405776a378ae2ce42155d5148f85d9b7b3121ccb/ScriptGenerator/InstallerScriptGenerator.exe -------------------------------------------------------------------------------- /ScriptGenerator/InstallerScriptGenerator.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ScriptGenerator/InstallerScriptGenerator.vshost.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahargv/redisql/405776a378ae2ce42155d5148f85d9b7b3121ccb/ScriptGenerator/InstallerScriptGenerator.vshost.exe -------------------------------------------------------------------------------- /ScriptGenerator/InstallerScriptGenerator.vshost.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ScriptGenerator/InstallerScriptGenerator.vshost.exe.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ScriptGenerator/SqlClrDeclarations.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahargv/redisql/405776a378ae2ce42155d5148f85d9b7b3121ccb/ScriptGenerator/SqlClrDeclarations.dll -------------------------------------------------------------------------------- /SqlClrDeclarations/Attributes/ExportedFunctionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SqlClrDeclarations.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Method)] 6 | public class SqlInstallerScriptGeneratorExportedFunction : SqlInstallerScriptGeneratorExportedAttributeBase 7 | { 8 | public string SqlReturnType { get; set; } 9 | 10 | public SqlInstallerScriptGeneratorExportedFunction(string functionName, string schemaName) 11 | { 12 | Name = functionName; 13 | SchemaName = schemaName; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SqlClrDeclarations/Attributes/SqlInstallerScriptGeneratorExportedAttributeBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SqlClrDeclarations.Attributes 4 | { 5 | public class SqlInstallerScriptGeneratorExportedAttributeBase : Attribute 6 | { 7 | public string SchemaName { get; set; } 8 | public string Name { get; set; } 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SqlClrDeclarations/Attributes/SqlInstallerScriptGeneratorExportedProcedure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SqlClrDeclarations.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Method)] 6 | public class SqlInstallerScriptGeneratorExportedProcedure : SqlInstallerScriptGeneratorExportedAttributeBase 7 | { 8 | public SqlInstallerScriptGeneratorExportedProcedure(string functionName, string schemaName) 9 | { 10 | Name = functionName; 11 | SchemaName = schemaName; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /SqlClrDeclarations/Attributes/SqlParameterAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SqlClrDeclarations.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Parameter)] 6 | public class SqlParameterAttribute : Attribute 7 | { 8 | public object DefaultValue { get; set; } 9 | public string Name { get; set; } 10 | public string SqlType { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SqlClrDeclarations/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using SqlClrDeclarations.Attributes; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("SqlClrDeclarations")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("SqlClrDeclarations")] 14 | [assembly: AssemblyCopyright("Copyright © 2015")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | // The following GUID is for the ID of the typelib if this project is exposed to COM 25 | [assembly: Guid("56c24720-8053-4cf5-8bf8-bae7dba78424")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | [assembly: AssemblyVersion("1.0.0.0")] 38 | [assembly: AssemblyFileVersion("1.0.0.0")] 39 | -------------------------------------------------------------------------------- /SqlClrDeclarations/SqlClrDeclarations.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {56C24720-8053-4CF5-8BF8-BAE7DBA78424} 8 | Library 9 | Properties 10 | SqlClrDeclarations 11 | SqlClrDeclarations 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 58 | --------------------------------------------------------------------------------