范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

SQLSERVER居然也能调C代码?

  一:背景1. 讲故事
  前些天看到一个奇怪的 Function 函数,调用的是 C# 链接库中的一个 UserLogin 方法,参考代码如下:  CREATE FUNCTION dbo.clr_UserLogin (     @name	AS  NVARCHAR(100),     @password AS NVARCHAR(100) ) RETURNS INT  AS EXTERNAL NAME asmXXX.[xxx.CLRFunctions].UserLogin; GO
  这就让我产生了很大的兴趣,众所周知 SQLSERVER 是 C++ 写的,那这里的 C++ 怎么和 C# 打通呢? 而且 C# 是一门托管语言,需要 JIT 将其 native 化,这个 JIT 又在哪里呢? 带着这些疑问一起研究下吧。 二:互通原理研究1. 一个简单的例子
  首先写一段简单的 C# 代码,然后把它编译成 dll。  namespace AQMN.Bussiness {     public class UserFunctions     {         public static string UserLogin(string username, string password)         {             var random = new Random();              var isSuccess = random.Next() % 2 == 0;              return isSuccess ? "登录成功" : "登录失败";         }     } }
  接下来需要做的就是数据库参数配置,开启 CLR 支持,并且指定某个数据库支持  unsafe   模式。 EXEC sp_configure "clr enabled", 1; RECONFIGURE; GO  ALTER DATABASE MyTestDB SET TRUSTWORTHY ON; GO
  为了能够调到 C# 的  UserLogin   方法,需要 SQLSERVER 先导入这个程序集,然后再以 Function 映射其中方法即可,参考代码如下: CREATE ASSEMBLY clr_AQMN_Bussiness FROM "D: et6SQLCrawlAQMN.BussinessbinDebugAQMN.Bussiness.dll" WITH PERMISSION_SET = UNSAFE; GO  CREATE FUNCTION dbo.clr_UserLogin (     @username AS NVARCHAR(100), 	@password AS NVARCHAR(100) ) RETURNS NVARCHAR(100) AS EXTERNAL NAME clr_AQMN_Bussiness.[AQMN.Bussiness.UserFunctions].UserLogin; GO
  创建完了之后,可以观察  assembly   开头的几个系统视图。 SELECT * FROM sys.assemblies SELECT * FROM sys.assembly_files; SELECT * FROM sys.assembly_modules;
  看起来没啥问题,接下来调用一下刚才创建的  clr_UserLogin   函数。 SELECT dbo.clr_UserLogin(N"jack",N"123456") AS "State" GO 10
  从图中看登录结果是随机的,说明 C# 的 Random 函数起到了作用,非常有意思。 2. WinDbg 观察
  从案例的运行结果看,推测在 SQLSERVER 中应该承载了一个 CLR 运行环境,那是不是这样呢?可以用 WinDbg 附加到  sqlservr.exe   进程,用 lm 观察下模块加载情况。 0:092> lm start             end                 module name  ... 00007ff8`d3960000 00007ff8`d3aaf000   clrjit     (deferred)     00007ff8`de040000 00007ff8`deb02000   clr        (deferred)      ...  0:092> !eeversion 4.8.4300.0 free Server mode with 12 gc heaps SOS Version: 4.8.4300.0 retail build
  从输出看果然加载了  clr   和 clrjit   动态链接库,当前还是 gc server   模式,哈。
  接下来再验证一个问题,既然  clr_UserLogin   函数会显示 登录成功/登录失败  ,那必然会调用 C# 的 UserLogin   方法,可以在 WinDbg   中对 UserLogin   方法下一个断点观察一下这个调用过程。 0:090> !name2ee AQMN.Bussiness!AQMN.Bussiness.UserFunctions.UserLogin Module:      00007ff87ee37988 Assembly:    AQMN.Bussiness, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Token:       0000000006000001 MethodDesc:  00007ff87ee38020 Name:        AQMN.Bussiness.UserFunctions.UserLogin(System.String, System.String) JITTED Code Address: 00007ff87ec560d0  0:090> bp 00007ff87ec560d0 0:090> g
  从输出信息看 UserLogin 方法已经被 JIT 过了,用 bp 下完断点之后,继续 g,然后在 SSMS 上再次执行查询就可以成功命中啦。  0:090> k  # Child-SP          RetAddr               Call Site 00 000000df`1557ae48 00007ff8`7ee500b6     0x00007ff8`7ec560d0 01 000000df`1557ae50 00007ff8`7ec55ef1     0x00007ff8`7ee500b6 02 000000df`1557aeb0 00007ff8`de04222e     0x00007ff8`7ec55ef1 03 000000df`1557af00 00007ff8`a2b79ff3     clr!UMThunkStub+0x6e 04 000000df`1557af90 00007ff8`a2b741bd     sqllang!CallProtectorImpl::CallWithSEH const >+0x23 05 000000df`1557afc0 00007ff8`a2b6bfc4     sqllang!CallProtectorImpl::CallExternalFull const >+0x2dd 06 000000df`1557b130 00007ff8`a2bda602     sqllang!CAppDomain::InvokeClrFn+0xd4 07 000000df`1557b1d0 00007ff8`aef51ee7     sqllang!UDFInvokeExternalImpl+0xb72 08 000000df`1557b7e0 00007ff8`9de52e24     sqlTsEs!CEsExec::GeneralEval4+0xe7 09 000000df`1557b8b0 00007ff8`9de52d64     sqlmin!CQScanProjectNew::EvalExprs+0x18f 0a 000000df`1557b920 00007ff8`9ddd8759     sqlmin!CQScanProjectNew::GetRow+0x98 0b 000000df`1557b970 00007ff8`9ddc73de     sqlmin!CQScanLightProfileNew::GetRow+0x19 0c 000000df`1557b9a0 00007ff8`a25e51d7     sqlmin!CQueryScan::GetRow+0x80 0d 000000df`1557b9d0 00007ff8`a32a78b2     sqllang!CXStmtQuery::ErsqExecuteQuery+0x3d8 0e 000000df`1557bb40 00007ff8`a2bc2451     sqllang!CXStmtSelect::XretDoExecute+0x342 0f 000000df`1557bc10 00007ff8`a2b733d3     sqllang!UM_LoopbackForStatementExecution+0x191 10 000000df`1557bd00 00007ff8`de48e940     sqllang!AppDomainCallback >+0x23 11 000000df`1557bd40 00007ff8`de48e193     clr!ExecuteInAppDomainHelper+0x40 12 000000df`1557bd80 00007ff8`a2b79f39     clr!CorHost2::ExecuteInAppDomain+0x3a0 13 000000df`1557c0a0 00007ff8`a2b73a86     sqllang!CallProtectorImpl::CallWithSEH >+0x29 14 000000df`1557c0d0 00007ff8`a2b6c2d0     sqllang!CallProtectorImpl::CallExternalFull >+0x186 15 000000df`1557c170 00007ff8`a32a72f4     sqllang!CAppDomain::LoopbackForStatementExecution+0x180 16 000000df`1557c230 00007ff8`a32a79ad     sqllang!CXStmtQuery::XretCLRExecute+0x104 17 000000df`1557c2a0 00007ff8`a25e4a65     sqllang!CXStmtSelect::XretExecute+0x4a 18 000000df`1557c370 00007ff8`a25e44a8     sqllang!CMsqlExecContext::ExecuteStmts<1,1>+0x8f2 19 000000df`1557cf10 00007ff8`a25e3a2c     sqllang!CMsqlExecContext::FExecute+0x936 1a 000000df`1557def0 00007ff8`a25ee67b     sqllang!CSQLSource::Execute+0xc5c 1b 000000df`1557e3d0 00007ff8`a25ed815     sqllang!process_request+0xca6 1c 000000df`1557ead0 00007ff8`a25ed5ef     sqllang!process_commands_internal+0x4b7 1d 000000df`1557ec00 00007ff8`b1e46523     sqllang!process_messages+0x1d6 1e 000000df`1557ede0 00007ff8`b1e46e6d     sqldk!SOS_Task::Param::Execute+0x232 1f 000000df`1557f3e0 00007ff8`b1e46c75     sqldk!SOS_Scheduler::RunTask+0xa5 20 000000df`1557f450 00007ff8`b1e6b160     sqldk!SOS_Scheduler::ProcessTasks+0x39d 21 000000df`1557f570 00007ff8`b1e6aa5b     sqldk!SchedulerManager::WorkerEntryPoint+0x2a1 22 000000df`1557f640 00007ff8`b1e6afa4     sqldk!SystemThreadDispatcher::ProcessWorker+0x3ed 23 000000df`1557f940 00007ff8`f6d86fd4     sqldk!SchedulerManager::ThreadEntryPoint+0x3b5 24 000000df`1557fa30 00007ff8`f865cec1     KERNEL32!BaseThreadInitThunk+0x14 25 000000df`1557fa60 00000000`00000000     ntdll!RtlUserThreadStart+0x21
  果然是一个 request 请求,然后达到了托管方法  UserLogin  ,顶部的三行线程栈可以用 !clrstack   具意下。 0:090> !clrstack OS Thread Id: 0x6df4 (90)         Child SP               IP Call Site 000000df1557ae48 00007ff87ec560d0 AQMN.Bussiness.UserFunctions.UserLogin(System.String, System.String) 000000df1557ae50 00007ff87ee500b6 DynamicClass.SQLCLR_Eval(IntPtr, IntPtr, IntPtr) 000000df1557aeb0 00007ff87ec55ef1 DomainBoundILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64) 000000df1557bf18 00007ff8de04222e [ContextTransitionFrame: 000000df1557bf18]   三:总结
  SQLSERVER 内嵌了 CLR,让 sqlservr 进程成了一种托管和非托管的混合环境,不知道是好事还是坏事,在我的分析旅程中这种混合环境下看过太多的 堆破坏 问题,但不管怎么说,托管的 C#,VB,F# 可以助 SQLSERVER 更加强大。

光触媒在什么时间添加到食品中去的光触媒技术是1967年东京大学本多建一教授发现的,在光照下二氧化钛电极可以将水分解成氢气与氧气。2015年,日本研发光触媒净化技术,从火山矿石中提取铂元素,加入到光触媒液体中,引起看完这组震撼的图片,才知道时间的力量有多可怕!话说,世界上最奇妙的莫过于时间,它是最公正的法官,无论贫富贵贱,每个人一天都只有24小时,不会多一秒,也不会少一分但它同样是最残酷的东西,在你我不注意间不紧不慢地溜走虽然看不见摸不蜂王浆对身体有什么好处?吃对养生,但若吃错也会伤身,注意这几点对于喜欢纯天然的朋友来说,蜂王浆是一款老少皆宜的高级营养品,适合家里的每一位成员,并且拿去送礼也是一份非常有面子的礼物。之所以受到如此的青睐,主要还是因为蜂王浆的实际作用非常明显,腰椎间盘突出,有哪些锻炼误区腰椎间盘突出,有哪些锻炼误区腰椎间盘突出症患者应该如何锻炼,需要结合自身的病情而定,如果疼痛没有缓解,甚至加重的情况下,可以在医生的指导下服用一些药物,同时配合做一些康复锻炼。但是如何预防结石复发?专家说注意以下5点,能很好的预防复发随着人们生活水平的提高,饮食结构也在不断变化。而结石是一种常见的疾病,发病率越来越高。如何预防结石复发?结石5年复发率约为50研究表明,如果不进行干预,结石5年复发率约为50。这意女人经常腰酸背疼,可能是子宫在遭难!保护子宫,治疗宫寒你是不是也经常腰酸背痛,特别是女性都常犯的老毛病,但是很多女性误认为是疲劳或腰椎方面的问题。实际上,腰酸背痛可以由多种因素引起,尤其对女性而言,月经病带下病妇科病等这些妇科病都均可吃的不多,为什么还是很胖?多半是这个原因!生活中人们会遇到这样的情况,有些人怎么吃也不会胖,一直保持着骨感身材。而有些人吃的并不多,但依然很胖,喝口水都长肉并不夸张。那么追根溯源,原因到底有哪些呢?脾虚脏腑器官出现变化是不一清肝,二排毒,三助眠,春季要常吃,遇到了别手软,养肝护肝肝是人体非常重要的器官,既排毒也藏血,中医有百病从肝治,养肝如养命的说法。身体经过整个冬天的蛰伏,在春季逐渐复苏,全身气血开始流畅振奋,肝气也得以舒展,所以春季是调养肝脏的最佳季节王者荣耀当前版本,中路法刺英雄逐渐式微,局中对抗何去何从?前言都知道,中路法师英雄其实是可以分为多个类别的,其中就包括了功能性法师,辅助性法师,大法师,以及法刺英雄。但就目前版本而言,中路法刺英雄的对局环境很不好,说是逐渐式微一点都不为过武陵源旅拍火辣上线体验式消费倍受青睐张家界美景冠绝天下,旅拍能让张家界走进千家万户。(吴勇兵摄)张家界魅力湘西景区旅拍风情街,一拔接一拔的游人身着艳丽的民族服饰。(吴勇兵摄)在旅拍摄影师的镜头中穿越般与高低错落的转角利物浦传奇,伊斯兰世界之光默罕默德萨拉赫在足球的王国里,论名气,萨拉赫不输梅西和C罗,他可以说是阿拉伯足球之神,埃及年轻一代眼中的民族英雄,心中追捧热爱的全民偶像。可以这样说,在埃及,如果你不知道现任埃及总统是谁没关系,
立春遇见济宁万物迎新,春天你好盼望着,盼望着东风来了春天的脚步近了立春是一个重要的节气它是二十四节气中的第一个节气春,代表着温暖生长立春意味着鸟语花香的春季即将开始春是希望,生机勃勃立春一过伴随着寒气渐消,天地自我救赎走向快乐和宁静的必经之路从呱呱坠地那一刻,人类开始接受上一辈的认知,小小的脑袋空瓶不断输入,从行动到思维不断受到引导和规范。此阶段基本要持续到初中,意味着被输入认知是整个童年时期的常态,这个阶段是人类建立听听发生在产房里的那些故事,生个孩子能让你看清许多人!女人生孩子,哇的一声啼哭后,护士把孩子先抱出来了。老公兴奋激动地跑去看孩子,而女人的母亲还等在手术室门外。男人过来问妈,怎么不去看孩子啊?母亲说你的孩子是出来了,我的孩子还在里面。北京冬奥精神宣讲团续写双奥故事光明日报记者董城2月3日,在北京冬奥会成功举办一周年之际,北京冬奥精神宣讲团来到延庆赛区,在中关村(延庆)体育科技前沿技术创新中心举办北京冬奥会一周年专场宣讲会。8位冬奥精神宣讲员快速备孕成功的绝招,建议收藏每一个女人都有一个妈妈梦,于是她们在结婚后开启了自己的备孕之路,但想象很丰满,现实很骨感,有很多备孕女性在备孕过程中遇到了很多问题,这就导致她们怀孕非常困难,那么,如何才能快速怀孕幼儿睡前故事霸王龙苏苏的黑牙保护牙齿新故事学堂推送的第4篇原创精品儿童睡前故事音频文字版儿童睡前故事霸王龙苏苏丛林故事集文字版霸王龙苏苏丛林故事集霸王龙苏苏的黑牙这一天,霸王龙一家正围坐在一起吃早餐,突然,小霸王龙苏小宝贝睡前童话故事三个恐龙好朋友我不挑食新故事学堂推送的第5篇原创精品儿童睡前故事音频文字版宝贝睡前童话故事三个恐龙好朋友文字版三个恐龙好朋友我不挑食太阳从东方升起,明媚的阳光洒满了大地,美好的一天又开始了。翼龙小米一大珊瑚贝壳海胆,机场高速旁居然藏着一片海?市民小庄是云南大学古生物研究重点实验室的在读研究生,前两天,他去长水机场送朋友的时候,偶然发现机场高速收费站旁,有一片类似喀斯特地貌的景观,好奇的他专门绕过去查看,哪知还真发现了一西湖之行这家博物馆不容错过近十几年来,各地博物馆不少都建了新馆舍,观众观展体验也大为提升。在新馆建立后新老馆舍并用的不太多,这里就有浙江省博物馆。虽然没有新馆高大宽绰,但浙博老馆已成为浙江历史的一部分,这样诺伊尔复出后会全力以赴夺回自己的位置,别幻想我会让位给他人直播吧2月4日讯近日,正在养伤的德国国门诺伊尔接受了TA采访,采访中他谈到了自己在拜仁和德国国家队的前景。问前德国国门托尼舒马赫建议你在生涯最后几年从国家队退役,专注于为拜仁效力,蔡斌主动求变,跑动型接应将再现中国女排,龚翔宇位置或受到冲击新一期中国女排集训名单公布之后,除主力球员之外,郑益昕几乎是唯一一名众望所归的入选球员。而且本次郑益昕的入选也背负了主教练蔡斌很大的期望。据蔡斌介绍说郑益昕的特点是跑动灵活,适合接