2011年8月24日星期三
2011年7月5日星期二
PHP 中的 ==null;is_null();empty()
==null: 0, null, ''
//change to:
function is_emptystring_or_null($str) {
return (is_null($str) || ($str === ''));
}
is_null(): ===null
isset is_null ===null ==null empty
null | F | T | T | T | T |
true | T | F | F | F | F |
false | T | F | F | T | T |
0 | T | F | F | T | T |
1 | T | F | F | F | F |
\0 | T | F | F | F | F |
unset | F | T | T | T | T |
"" | T | F | F | T | T |
[] | T | F | F | T | T |
2011年5月5日星期四
applet授权数字签名【转】
1.假设你的需要压缩的类文件存在的包为:cn.mbq.test1和cn.mbq.test2
2.进入你的classes目录,在DOS窗口中执行命令:jar cf mytest.jar cn.mbq.test1 cn.mbq.test2
3.执行命令后你会在当前目录中找到mytest.jar文件,这个就是刚才生成的档案文件。你可以修改它的后缀为rar,然后使用winrar压缩程序打开它查看看是否正确。
jar -cvf MyApplet.jar class
打包文件夹下所有class jar -cf MyApplet.jar com\company\applet
二、使用keytool工具生成密匙库
1.keytool工具位于${java_home}/bin目录下;
2.在DOS窗口中执行命令:keytool -genkey -keystore mytest.store -alias mbq
注意:mytest.store 是你的密匙库的名称,可以随意修改,后缀请不要修改!
mbq 为别名,这个也可以改成自己的名称
3.执行上述命令后,DOS窗口中会提示你输入keystore的密码、你的姓名、组织单位等等信息。这里要注意的是输入密码请记住,后面要用到的。在最后,我们输入y确认信息。然后再直接回车设置mbq的主密码和store密码一致即可!
三、使用keytool工具导出签名时用到的证书
1.在DOS窗口中执行命令:keytool -export -keystore mytest.store -alias mbq -file mbq.cert
注意:mytest.store 就是第二步生成的密匙库名称
mbq 也是在第二步中我们指定的别名
mbq.cert 为我们生成的证书的名称,可以自己修改名称,注意后缀不要改
2.命令执行成功,我们会在当前目录下找到一个mbq.cert文件,这个就是我们刚才生成的证书。
四、使用jarsigner工具签名jar压缩文档
1.jarsigner工具位于${java_home}/bin目录下;
2.在当前DOS窗口中执行命令:jarsigner -keystore mytest.store mytest.jar mbq
注意:mytest.store 就是我们在第二步中生成的密匙库名称
mytest.jar 就是我们这第一步压缩的jar文档
mbq 是提供者的名称,我们这里设置为我们的别名
再运行的Applet就可以访问本地了
嵌入Applet部分的写法:
OBJECT对象中的CODEBASE指的路径是相对当前页面的路径,是可以有效的.最后部署的时候只需要签名后的jar包就可以了,其他的文件都不需要
关于Html嵌入Applet的问题
标签的属性介绍
属性 含义
Width Applet在Html页面上的宽度
Height Applet在Html页面上的高度
Name Applet在Html页面上的名称,用于区名一个Html页面上的多个Applet
Code Applet类名,必须带后缀”class”当没有属性archive时,直接写类名当有属性archive时,必须带包名
Codebase Applet的类相对路径,相对于Html页面位置
Archive Applet所在Jar包的文件名
标签< PARAM>的属性介绍
属性 含义
Name Applet传入的参数名
Value Applet传入的参数值
当Applet 为一个Class类文件嵌入的写法
属性Code ==========Applet类名,必须带后缀名
属性CodeBase ---------------Class类文件相对于Html页面的相对路径
Applet为一个JAR包,嵌入Html的写法
属性Code ==========Applet类名,包括包名
属性CodeBase ----------------Applet JAR包相对于Html页面的相对路径
属性Archive -----------------------Applet Jar包文件名
对于需要授权的applet(如读取本地文件),进行数字签名后,在paint方法中可以读取本地文件,但放在自定义的方法中,通过js调用自定义的方法还是提示没有权限,不解
可以通过再建立一个线程类,在run方法中调用applet中读取本地文件的自定义方法,线程类可以在applet中的初始化方法init中建立,applet类当做参数传给线程类
JavaScript访问Applet
//JavaScript访问Applet属性
window.document.appletName.appletField (属性必须是public的,"window.document."也可以不写)
/JavaScript访问Applet方法
window.document.appletName.appletMethod (方法必须是public的,"window.document."也可以不写)
var result = appletName.appletMethod ("param"); //调用applet带参数的方法和有返回值的方法
打包jar文件必须把applet引用到的类全部打包进去,否则调用方法会找不到(对象不支持此属性或方法),或一些其他错误
文章转自:http://blog.csdn.net/zhaoyh82/archive/2009/05/19/4200897.aspx
如何突破Applet的安全限制
Java Applet 是用Java 语言编写的小应用程序,这些程序是直接嵌入到页面中,
由支持Java的浏览器(IE 或 Nescape等)解释执行,能够产生特殊效果的程序。
它可以大大提高Web页面的交互能力和动态执行能力。包含Applet的网页被称为Java-powered页,可以称其Java支持的网页。
二、Applet用法
1.确定包含在HTML文档中的Java Applet程序已经存在;
2.调用"applet"格式(以Java01.class 为例)
A.code属性:定义调用的Java Applet 程序名,要注意全名和大小写。
B.codebase属性:定义Java Applet 程序的路径或地址(URL),当Java Applet与HTML文档不在同一目录时用它来定位,
上面调用格式中codebase="javam"说明该Java Applet程序存放在"javam"目录里
(建议将Java Applet 程序和HTML文档放在同一目录)。
C.width和height属性:给出Java Applet程序显示区域以像素为单位的宽度和高度。
D.vspace和hspace属性:用来设置以像素为单位的竖直和水平边距。
E.align属性:控制Java Applet的对齐方式,取值如下:
left(屏幕的左边)
right(屏幕的右边)
top(与该行中最高项的顶部对齐)
texttop(与该行文本的顶部对齐)
middle(使该行的基线与该Java Applet程序显示域的中间对齐)
absmiddle(使该行的中间与该Java Applet程序显示域的中间对齐)
baseline(使该行的基线与该Java Applet的程序显示域的底部对齐)
bottom(使该行的基线与该Java Applet的程序显示域的底部对齐)
absbottom(使该行的底部与图像的底部对齐)
F.archive属性:用逗号分隔的归档文件列表(HTML 4.0 )
G.object属性:序列化的applet文件(HTML 4.0)
H.name属性:为应用的Applet 实例赋一具体的名字。
J.alt属性:为不支持Java Applet程序的浏览器显示你替代的文字,如果支持该属性被忽略。
I.另:为不支持Java Applet程序的浏览器显示你替代的文字,
还可以用在之间插入文字的方法进行,反之该插入文字被忽略不显示。
3.向 Applet 传递变量
A.确定该 Java Applet 程序所接受的变量名,比如 size、font两个变量;
B.在之间输入标记,
C.给标记加入name属性并设置为Java Applet中将接收值的变量名
D.加入value属性为前面定义好的变量赋值。
E.当浏览器遇到 标记中的标记时,它读进变量名和赋予的值传递给当前Java Applet中的命名变量。
三、Applet安全限制
在缺省的情况下,Applet在安全方面受到诸多的限制,几乎不能对系统进行任何“读”“写”的操作。
下面受限制的功能:
不允许Applet读本地系统上的文件。例如,下面的代码将出错:
File readFile=new File("/etc/passwd");
FileInputStrean readIn=new FileInputStream(readFile);
不允许Applet创建,修改或删除本地系统的文件。例如,下面的代码将出错:
//不能创建文件
File writeData=new File("write.txt");
FileOutputStream out= new FileOutputStream(writeData);
cut.write(1);
//不能修改或删除文件,不能更改文件名
File oldName =new File("one.txt");
File newName= new File("two.txt");
oldName.renameTo(newName);
File removeFile=new File("inport.dat");
removeFile.delete();
不允许Applet检查本地系统上文件是否存在。例如,下面的代码将出错:
File isHere = new File("grades.dbm");
isHere.exists();
不允许Applet在本地系统上创建目录。例如,下面的代码将出错:
File createDir= new File("mydir");
createDir.mkdir();
不允许Applet检查目录的内容。例如,下面的代码将出错:
String[] fileNames;
File lookAtDir= new File("/user/hisdir");
fileNames = lookAtDir.list();
不允许Applet检查文件的属性。例如,不允许检查文件的尺寸、类型、最后更改时间等、
例如,下面的代码将出错:
File checkFile= new File("this.dat");
ling checkSize;
boolean checkType;
long checkModTime;
checkSize= checkFile.length();
checkTyty= checkFile.isFile();
checkModTime= checkFile.lastModified();
Applet不能创建或装载Applet的机器的网络连接。
无论使用何种不同的网络Java类(包括:java.net.Socket,java.net.URL,and
java.DatagramSocket),这个规则都成立。例如,假设Applet被下载到www.trusted.org,
下面的代码将出错:
//不能打开TCP socket.
Socket mailSocket = new Socket("mail.nutrusted.org",25);
//不能使用URL对象
URL untrustedWeb=new URL("http://www.untrusted.org/");
URLConection agent= untrustedWeb.openConnection();
agent.connect();
//不能使用UDP数据报发送数据
InetAddress thetSize=new InetAddress("WWW.untrusted.org");
int thatPort=7;
byte[] data= new byte[100];
DatagramPacket sendPacket= new DatagramPacket(data,data.lenght,thatSize,thatPort);
DatagramSocket sendSocket=new datagramSocket();
sendSocket.send(sendPacket);
Applet不能充当网络服务器,监听或接收来自远程系统的连接请求。
例如,下面的代码将出错:
ServerSocket listener= new ServerSocket(8000);
listener.accept();
Applet不能执行任何本地计算机上的程序。例如,下面的代码将出错:
String command="DEL\AUTOEXEC.BAT";
Runtime systemCommands=Runtime.getRuntime();
systemCommands.exec(command);
不允许Applet装载动态库或定义本地方法调用。例如,下面的代码将出错:
Runtime systemCommands= Runtime.getRuntime();
systemCommands.loadLibrary("local.dll:);
在Java环境中,设置了一些标准的系统属性,
jaxa.lang.System.getProperty(String kcy) 方法可以出来访问这些属性,
对于Applet而言,某些系统属性是只读的。这些属性包括:file.separator,
java.class.path,java.class.version,java.home,java.vendor,
java.vendor.url,java.version,line.separator,os.arch,os.name,
os.version,path.separator,user.dir,user.home,user.name。
Applet不能操纵不在自己线程组中的任何线程。
Applet不能关闭JVM。例如,下面的代码将出错:
Runtime systemCommands=Runtime.getRuntime();
systemCommands.exit(0);
system.exit(0);
Applet不能创建SecurityManager或ClassLoader实体。
这些策略表达了一些严格的限制,应该清楚在缺省的情况下,
Applet可以做什么,不可以做什么,正确对待一些非编程方面的错误。
四、Applet数字签名
步骤一:将Applet Class打成Jar包
如:在命令行中执行以下的语句:
jar -cvf MyApplet.jar class
步骤二:(在网页中嵌入Applet)(如何在Html嵌入Apple方法见附录)
下面是嵌入Applet部分的写法:
步骤三:(生成证书及签名)
1、keytool -genkey -keystore pepper.store -alias pepper
这个命令用来产生一个密匙库,执行完毕后应该在c:/admin中产生一个pepper.store的文件,
这里的pepper是我自己的名字,你可以对它进行修改。另外在执行命令的时候还有提示
你输入密匙库的密码,这里你一定要记住,否则后面要用的时候无法输入。
2、keytool -eXPort -keystore pepper.store -alias pepper -file pepper.cert
这个命令用来产生签名时所要用的证书,同样这里的pepper也可以换成你自己需要的名字。
这个命令执行完后在c:/admin中产生一个pepper.cert的文件。
3、 jarsigner -keystore pepper.store MyApplet.jar pepper
这个命令用上面产生的证书将我们的jar文件进行了签名。
步骤四:新建一个策略文件,并把这些策略文件加入(修改文件)
1、在c:/admin中产生一个名为applet.policy的文件,其内容如下:
keystore "file:c: /admin/pepper.store", "JKS";
grant signedBy "pepper"
{ permission Java.io.FilePermission "<<ALL FILES>>", "read";=;
这个文件让由pepper签名的Applet拥有本地所有文件的读权限。
2、修改${java.home}/jre/lib/security目录下的java.security,找到下面这两行:
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
在下面添写第三行
policy.url.3=file:c: /admin/applet.policy
完成这个修改后我们在前面创建的applet.policy文件才有效。
步骤五:(转换html文件)
运行前面提到的HTMLConvert工具,将原有的FileReaderApplet.html转化成下面的形式:
<!--"CONVERTED_APPLET"-->
<!-- CONVERTER VERSION 1.3 -->
<!--
<APPLET CODE = "jcomponent.FileReaderApplet.class"
CODEBASE = "." ARCHIVE = "MyApplet.jar" WIDTH = 400 HEIGHT = 300
NAME = "TestApplet" ALIGN = middle VSPACE = 0 HSPACE = 0>
</APPLET>
-->
<!--"END_CONVERTED_APPLET"-->
大家不要看到这里的写法很复杂,但是这些都是由HTMLConvert工具自动实现的。
这个工具有命令行和图形界面两种运行方式。
好了,现在这个Applet可以运行读写文件的功能了。
如果你要考虑在Internet上实现这个Applet,那么你也不需要在所有的客户端均做上面的步骤,
你只需要在你的服务器上创建一个目录,
例如c:/admin,将这个目录映射为www.testApplet.com/admin。
这里的www.testApplet.com是一个假定的网址,将pepper.cert、pepper.store、
FileReaderApplet.html、MyApplet.jar以及applet.policy放在这个目录中,
然后修改applet.policy文件如下:
keystore "http:// www.testApplet.com/admin/pepper.store",
"JKS";grant signedBy "pepper"{
permission java.io.FilePermission "<<ALL FILES>>", "read";};
3、而每个客户端仅仅需要修改一下它们的${java.home}/jre/lib/security
目录下的java.security文件如下:
policy.url.1=file:${java.home}/lib/security/java.policypolicy.url.2=
file:${user.home}/.java.policypolicy.url.3=
http:// www.testApplet.com/admin/applet.policy
当然每个客户端还是需要安装JRE的。
Height Applet在Html页面上的高度
Name Applet在Html页面上的名称,用于区名一个Html页面上的多个
AppletCode Applet类名,必须带后缀”class”当没有属性archive时,
直接写类名当有属性archive时,必须带包名Codebase Applet的类相对路径,
相对于Html页面位置Archive Applet所在Jar包的文件名
标签< PARAM>的属性介绍
属性 含义
Name Applet传入的参数名
Value Applet传入的参数值
当Applet 为一个Class类文件嵌入的写法
属性Code ==========Applet类名,必须带后缀名
属性CodeBase ---------------Class类文件相对于Html页面的相对 路径
Applet为一个JAR包,嵌入Html的写法
属性Code ==========Applet类名,包括包名
属性CodeBase ----------------Applet JAR包相对于Html页面的相对路径
属性Archive -----------------------Applet Jar包文件名
五、Applet与js调用
javascript与applet之间能够相互通讯给我们带来了很多方便,Java与JavaScript互相补充,
以开发功能更完美的Web应用程序。B/S下能够充分利用java的优势,给我们带来更多的网络体验,
方便用户。我用的比较多的是利用Swing组件开发的应用程序利用applet实现B/s下架构, 这样能
够充分显示Swing组件的优势,便于系统升级,便于维护;还有就是在WEB下,有时客户端要使用
本地的硬件资源,我所知道的是通过applet来实现,通过applet去调用javaAPI
(jni,javacomm20-win32【详见http://www.iteye.com/topic/64859】)来实现。
不知道有没有类似applet的实现方式,我想应该有的。
我们具体来看看javascript与applet之间到底是怎样通讯的呢?
1.JavaScript访问Applet
代码
1.
2. //JavaScript访问Applet属性
3. window.document.appletName.appletField
(属性必须是public的,"window.document."也可以不写)
4. /JavaScript访问Applet方法
5. window.document.appletName.appletMethod
(方法必须是public的,"window.document."也可以不写)
2.Applet访问JavaScript
Live Connect提供了Java与JavaScript的接口,可以允许在Java Applet小程序中使用JavaScript。
需要用到一个jar包,在C:\WINNT\java\Packages目录下找,大概有5M多,
其实就是打开看哪个有netscape.javascript.JSObject。如果没有装个NetScape或从网上下都可以。
可以把它重命名为netscape.jar(不是必须的),一定要加入到classpath,目的是使开发的时候能够编译。
注意:部署时不需要包括netscape.jar,因为整个包会下载到客户端,影响速度。
代码
1. //引入netscape类
2. import netscape.javascript.JSObject;
3. import netscape.javascript.JSException; //可允许在小程序中处理异常事件
4.
5. win=JSObject.getWindow(this); // 获取JavaScript窗口句柄,引用当前文档窗口
6. doc=(JSObject)win.getMember("document"); // 访问JavaScript document对象
7. form=(JSObject)doc.getMember("textForm"); //访问JavaScript form对象
8. textField=(JSObject)form.getMember("textField");访问JavaScript text对象
9. text=(String) textField.getMember("value"); //获取文本区的值
10.
11. // 调用JavaScript的alert()方法
12. win.eval("alert(\"This alert comes from Java!\")");
13.
14. // 调用JavaScript的myFunction(message)方法
15. win.call("myFunction", new Object[]{"Hello"});//参数用数组的形势表示。
注意:你必须在 标记中加入MAYSCRIPT才能够调用JSObject对象,
不然会抛出JSException异常。你也不必初始化他们,在什么地方用就在什么地方用吧。
2011年2月15日星期二
将Ajax 传回的Html中附带的Javascript 变量定义为全局
比如 ajax返回:
var pickerObj_sms_send_time 在全局javascript中不被辨认(undefined).
解决办法:
将var pickerObj_sms_send_time 定义改为:
window.pickerObj_sms_send_time... 即可
2010年9月21日星期二
Cron Job Syntax
field allowed values
----- --------------
minute 0-59
hour 0-23
day of month 1-31
month 1-12 (or names, see below)
day of week 0-7 (0 or 7 is Sun, or use names)
Wenn du den Tag der Woche festlegst, beides Tag 0 und Tag 7 stellen beide den Sonntag da.
Ein feld mit einem Sternchen(*), steht immer für das erste bis letzte.
Namen für ‘Monat’ und ‘Tag der Woche’ können ebenso in den Feldern stehen. Benutze die ersten 3 Buchstaben des jeweiligen Tages oder Monats(die englische Bezeichnung), z.B. sun oder SUN für Sonntag oder mar / MAR für März..
Lasst uns einen blick auf 2 Cron Jobs aus dem Ersten Kapitel werfen:
* * * * * /usr/local/ispconfig/server/server.sh > /dev/null 2>> /var/log/ispconfig/cron.log
Das meint: führe /usr/local/ispconfig/server/server.sh > /dev/null 2>> /var/log/ispconfig/cron.log einmal pro Minute aus.
30 00 * * * /usr/local/ispconfig/server/cron_daily.sh > /dev/null 2>> /var/log/ispconfig/cron.log
Das meint: führe /usr/local/ispconfig/server/cron_daily.sh > /dev/null 2>> /var/log/ispconfig/cron.log einmal pro Tag um 00:30h.
Der Tag an dem das Kommando ausgeführt werden soll, kann in 2 Felder angegeben werden: Tag des Monats und Tag der Woche: Wenn beide Felder beschränkt sind(z.B. kein *), das Kommando wird wenn eins von den beiden in dem Moment zutrifft.Zum Beispiel, 30 4 1,15 * 5 würde ein Kommando bedeuten, welches um 4:30h am ersten und letzen jeden Monats gestartet werden würde, genau wie jeden Freitag.
Du kannst Schritte benutzen um Cron Jobs zu definieren:
Beispiele:
1,2,5,9 - mein jede erste, zweite, fünfte, und neunte (Minute, Stunde, Monat…).
0-4,8-12 - mein alle (Minuten, Stunden, Monate,…) on 0 bis 4 und von 8 bis 12.
*/5 - meint jede fünfte (Minute, Stunde, Monet, …).
1-9/2 ist das gleiche wie 1,3,5,7,9.
Stufen oder Listen von Namen sind nciht erlaubt(Wenn du Namen anstelle der Nummern für Monate und Tage nimmst- z.B., Mon-Wen ist nicht möglich)
1,7,25,47 */2 * * * Kommando
Meint: starte Kommando jede 2. Stunde in der ersten, siebenten, 25. und 47. Minute.
Anstatt der ersten 5 felder, eine on 8 Speziellen Bedingungen können auftauchen:
string meaning
------ -------
@reboot Run once, at startup.
@yearly Run once a year, ”0 0 1 1 *”.
@annually (same as @yearly)
@monthly Run once a month, ”0 0 1 * *”.
@weekly Run once a week, ”0 0 * * 0″.
@daily Run once a day, ”0 0 * * *”.
@midnight (same as @daily)
@hourly Run once an hour, ”0 * * * *”.
Du kannst ebenso name=value paare in einem crontab benutzen um variablen von Cron Jobs zu definieren:
-----------------------------------------------------------------
# benutze /bin/bash um Kommandos zu starten, anstelle der standart /bin/sh
SHELL=/bin/bash
# Maile alle Ausgaben zu exampleuser, egal von wem der crontab ist
MAILTO=exampleuser
# Setze die PATH ariable um sicher zu stellen, das alle Kommandos in einem crontab gefunden werden
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
* * * * * my_command
--------------------------------------------------------------------
Bitte beachte: wenn du keine PATH variable in einem crontab gesetzt hast, benutze immer volle Pfade in dem crontab um sicher zu stellen, das das Kommando gefunden wird und angewendet werden kann. Zum Beispiel, anstatt rsync zu schrieben, solltest du besser /usr/bin/rsync schreiben.Benutze which um den vollen Pfad des Programm herauszufinden:
---------------
which rsync
---------------
server1:~# which rsync
/usr/bin/rsync
server1:~#
Siehe
--------------
man 5 crontab
--------------
Um mehr über die Syntax on Cron jobs zu lernen.
2010年9月20日星期一
Mysql UDF (转贴)
最近公司在做个SNS子项目,需要把交易系统中的交易数据实时地发送到SNS子系统中。最自然的设计是修改各个交易模块,将数据向SNS系统传输。但是在评审和开发的时候遇到了不小的阻力。理由很简单,这些修改直接影响系统的核心交易模块,引入了一定的风险。综合考虑后,决定增加个类似于Memcached Functions for MySQL的备选方案。SNS子系统虽然大量地使用了cache,但是没有使用Memcached或EHCache,原因是这些cache实现无法满足所有的需求。最初的想法是在UDF中使用ActiveMQ CPP,将消息直接发送到SNS子系统的cache中。不过最终还是放弃了这种比较激进的做法,而是在UDF中将数据通过socket发送到某个Java程序,然后再对数据进行分类处理后,转发给SNS cache。
关于user-defined function(UDF),在MySQL的官方文档上有比较详细的说明。为了使用UDF,必须要动态链接mysqld,也就是不能使用--with-mysqld-ldflags=-all-static,而是应该使用--with-mysqld-ldflags=-rdynamic。UDF通常需要用C/C++编写,如果要编写一个名为xxx的UDF,那么需要定义如下的C/C++方法:
- xxx() (required)。这个方法的返回值就是UDF的结果。SQL数据类型和C/C++类型之间的对应关系是:varchar char *;INTEGER long long;REAL double;DECIMAL char *等。
- xxx_init() (optional)。xxx()对应的初始化方法。该方法通常用来检查xxx()方法的参数(或者进行参数类型的转换),分配内存,指定返回值的最大长度等。
- xxx_deinit() (optional)。xxx()对应的清理方法。在这个方法中应该释放之前分配的内存。
当在SQL中调用名为XXX()的UDF时,MySQL会首先尝试调用名为xxx_init() 的方法,如果该方法返回false,那么MySQL会终止SQL的执行,并返回一个error message(在xxx_init()中保存在message参数中的以null结尾的字符串,最大长度为 MYSQL_ERRMSG_SIZE)。否则MySQL会对每个row调用xxx() 方法。在所有的row都被处理后,MySQL会调用xxx_deinit() 方法来执行相应的清理工作。对于那些象SUM()之类的聚集函数,还有一些其他的C/C++函数需要编写。需要注意的是,如果采用C++编写UDF,由于C++的"name mangling"会导致MySQL无法找到对应的C++函数,因此需要将函数声明包含在extern "C" { ... }中。以下是这些函数的例子:
my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char *xxx(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);
void xxx_deinit(UDF_INIT *initid);
initid参数会被传递到所有三个函数中(用于在这三个函数中共享数据),它指向一个UDF_INIT结构体。关于该结构体的成员,可以参考MySQL的在线文档。args参数指向一个UDF_ARGS结构体,它有如下成员:
- unsigned int arg_count。参数的个数。
- enum Item_result *arg_type。参数的类型。可选值有STRING_RESULT, INT_RESULT, REAL_RESULT, and DECIMAL_RESULT。DECIMAL_RESULT类型的值是以char *的形式传入到函数中的,因此处理方式同STRING_RESULT类型参数。如果xxx_init()中对该成员赋值,例如args->arg_type[0] = STRING_RESULT;那么MySQl会在调用xxx()是对 相应的参数进行强制地类型转换。
- char **args。参数值。如果参数值是NULL,那么args->args[i]是一个空指针(0)。对于STRING_RESUL类型的参数,那么可以通过 args->args[i]访问该字符串,字符串的长度是args->lengths[i](不要假定该字符串是以null结尾的)。对于INT_RESULT类型的参数,通过long long int_val = *((long long*) args->args[i]);进行访问。对于REAL_RESULT类型参数,通过double real_val = *((double*) args->args[i]);进行访问。对于DECIMAL_RESULT类型参数,处理方式同STRING_RESULT。
- unsigned long *lengths。在xxx_init()函数中,其值是字符串参数的最大长度。在xxx()函数中,其值是字符串参数的实际长度。对于INT_RESULT 或者REAL_RESULT类型参数,其值始终是最大可能值。
- char *maybe_null。在xxx_init()函数中,其值表明该参数是否可以为null。
- char **attributes。参数名。默认情况下是SQL中的表达式文本(同样,不要假定该字符串是以null结尾的)。
- unsigned long *attribute_lengths。参数名的字符串长度。
以下是个UDF C代码的片段:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "mysql.h"
///////////////////////////////////////////////////
extern "C" {
//
my_bool send_message_open_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char * send_message_open(UDF_INIT *initid, UDF_ARGS *args, char* result, unsigned long *length, char *is_null, char *error);
void send_message_open_deinit(UDF_INIT *initid);
//
my_bool send_message_close_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char * send_message_close(UDF_INIT *initid, UDF_ARGS *args, char* result, unsigned long *length, char *is_null, char *error);
void send_message_close_deinit(UDF_INIT *initid);
//
my_bool send_message_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char * send_message(UDF_INIT *initid, UDF_ARGS *args, char* result, unsigned long *length, char *is_null, char *error);
void send_message_deinit(UDF_INIT *initid);
}
////////////////////////////////////////////////////
// Open
////////////////////////////////////////////////////
my_bool send_message_open_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
// Validation
if(args->arg_count != 2) {
strcpy(message,"usage: select send_message_open('10.15.3.68', 7777)");
return -1;
} else if(args->arg_type[0] != STRING_RESULT || args->arg_type[1] != INT_RESULT){
strcpy(message,"usage: select send_message_open('10.15.3.68', 7777)");
return -1;
} else {
return 0;
}
}
char * send_message_open(UDF_INIT *initid, UDF_ARGS *args, char* result, unsigned long *length, char *is_null, char *error){
...
}
void send_message_open_deinit(UDF_INIT *initid) {
}
...
编译:
g++ -I/usr/local/mysql/include/mysql/ -shared -o send_message.so send_message.c
编译后需要将so文件拷贝到MySQL可以加载的位置,如:
cp send_message.so /usr/local/mysql6320/lib/mysql/plugin/
在MySQL中创建UDF:
DROP FUNCTION IF EXISTS send_message_open;
DROP FUNCTION IF EXISTS send_message_close;
DROP FUNCTION IF EXISTS send_message;
CREATE FUNCTION send_message_open RETURNS STRING SONAME 'send_message.so';
CREATE FUNCTION send_message_close RETURNS STRING SONAME 'send_message.so';
CREATE FUNCTION send_message RETURNS STRING SONAME 'send_message.so';
测试:
select send_message_open('10.15.3.68', 7777);
select send_message('test message');
select send_message_close();