与系统或者软件相关的错误信息一般都在控制面板,管理工具,事件查看器下。
成都创新互联服务项目包括荣成网站建设、荣成网站制作、荣成网页制作以及荣成网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,荣成网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到荣成省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
PostgreSQL 提供按行与按语句触发的触发器。按行触发的触发器函数为触发语句影响的每一行执行一次;按语句触发的触发器函数为每条触发语句执行一次,而不管影响的行数。特别是,一个影响零行的语句将仍然导致按语句触发的触发器执行。这两种类型的触发器有时候分别叫做行级触发器和语句级触发器。触发器还通常分成 before 触发器和 after 触发器。语句级别的"before"触发器通常在语句开始做任何事情之前触发,而语句级别的"after"触发器在语句结束时触发。行级别的"before"触发器在对特定行进行操作之前触发,而行级别的"after"触发器在语句结束的时候触发(但是在任何语句级别的"after"触发器之前)。
一个触发器是一种声明,告诉数据库应该在执行特定的操作的时候执行特定的函数。触发器可以定义在一个 INSERT, UPDATE, DELETE 命令之前或者之后执行,要么是对每行执行一次,要么是对每条 SQL 语句执行一次。如果发生触发器事件,那么将在合适的时刻调用触发器函数以处理该事件。触发器函数必须在创建触发器之前,作为一个没有参数并且返回 trigger 类型的函数定义。触发器函数通过特殊的 TriggerData 结构接收其输入,而不是用普通的函数参数方式.
注意:
一.按语句触发的触发器应该总是返回 NULL.
二.如果必要,按行触发的触发器函数可以给调用它的执行者返回一行数据(一个类型为 HeapTuple 的数值),那些在操作之前触发的触发器有以下选择
1. 它可以返回 NULL 以忽略对当前行的操作。这就指示执行器不要执行调用该触
发器的行级别操作(对特定行的插入或者更改)。
2.只用于 INSERT 和 UPDATE 行触发器:返回的行将成为被插入的行或者是成为
将要更新的行。这样就允许触发器函数修改将要被插入或者更新的行。
一个无意导致任何这类行为的在操作之前触发的行级触发器必须仔细返回那个被当作新行传进来的行。也就是说,对于 INSERT 和 UPDATE 触发器而言,是 NEW 行,对于 DELETE触发器而言,是 OLD 行。
三. 对于在操作之后触发的行级触发器,其返回值会被忽略,因此可以回NULL。
下面通过具体的例子来说明在postgresql中触发器的建立和使用(老规矩先写代码然后讲解)
#include postgres.h
#include executor/spi.h
#include funcapi.h
#include commands/trigger.h
#include fmgr.h
extern Datum pg_trigf(PG_FUNCTION_ARGS);
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(pg_trigf);
Datum
pg_trigf(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *)fcinfo-context;
HeapTuple rettuple = NULL;
int ret;
int proc; /* to store the value of SPI_processed (actual row number)*/
/* to be sure this function will be called by trigger */
if (!(CALLED_AS_TRIGGER(fcinfo))) {
elog(ERROR, "trigf: not called by triggermanager");
}
/* should be fired by statement */
if (TRIGGER_FIRED_FOR_ROW(trigdata-tg_event)) {
elog(ERROR, "cannot process row events");
}
/* should be fired before event */
if (TRIGGER_FIRED_AFTER(trigdata-tg_event)) {
elog(ERROR, "must be fired before event");
}
/* connect spi manager */
if ((ret = SPI_connect()) 0) {
elog(INFO, "SPI_connect failed: SPI_connectreturned: %d", ret);
return PointerGetDatum(rettuple);
}
/* check the permanent table name(perm_user) existsor not*/
ret = SPI_exec("SELECT tablename FROM pg_tables WHERE tablename LIKE'perm!_user' ESCAPE '!';", 1);
proc = SPI_processed;
if (ret != SPI_OK_SELECT) {
elog(INFO, "SPI_exec execute error: user table.");
SPI_finish();
return PointerGetDatum(rettuple);
}
/* create the permanent table(perm_user) if it does not exist */
if (proc 1) {
/* create permanent table: perm_user */
ret = SPI_exec("CREATE TABLE perm_user ASSELECT * FROM tbl_user;", 0);
if (ret != SPI_OK_SELINTO ) {
elog(INFO, "SPI_execexecute error: fail to create perm_user");
SPI_finish();
returnPointerGetDatum(rettuple);
}
/* set attribute to perm_user */
ret = SPI_exec("ALTER TABLE perm_user ADD PRIMARYKEY (user_name);", 0);
if (ret != SPI_OK_SELINTO) {
elog(INFO, "SPI_execexecute error: fail to add primary key to perm_user");
SPI_finish();
returnPointerGetDatum(rettuple);
}
/* set attribute to perm_user*/
ret = SPI_exec("ALTER TABLE perm_user ALTERuser_passwd SET NOT NULL;", 0);
if (ret != SPI_OK_SELINTO) {
elog(INFO, "SPI_execexecute error: fail to set attribute to password.");
SPI_finish();
returnPointerGetDatum(rettuple);
}
}
.....
/* check the permanent table name(perm_member) exists or not */
ret = SPI_exec("SELECT tablename FROM pg_tables WHERE tablename LIKE'perm!_member' ESCAPE '!';", 1);
proc = SPI_processed;
if (ret != SPI_OK_SELECT) {
elog(INFO, "SPI_exec execute errortbl_member");
SPI_finish();
return PointerGetDatum(rettuple);
}
/* create the permanent table(perm_member) if it does not exist */
if (proc 1) {
/* create permanent table: perm_member */
ret = SPI_exec("CREATE TABLE perm_member ASSELECT * FROM tbl_member;", 0);
if (ret != SPI_OK_SELINTO) {
elog(INFO, "SPI_execexecute error");
SPI_finish();
returnPointerGetDatum(rettuple);
}
/* set attribute to perm_member */
ret = SPI_exec("ALTER TABLE perm_member ADDCONSTRAINT user_fk FOREIGN KEY (user_name) REFERENCES perm_user(user_name) ONDELETE CASCADE ON UPDATE CASCADE;", 0);
if (ret != SPI_OK_UTILITY) {
elog(INFO, "SPI_execexecute error: fail to set attribute to user_name.");
SPI_finish();
returnPointerGetDatum(rettuple);
}
/* set attribute to perm_member */
ret = SPI_exec("ALTER TABLE perm_member ADDCONSTRAINT group_fk FOREIGN KEY (grp_name) REFERENCES perm_group(grp_name) ONDELETE CASCADE ON UPDATE CASCADE;", 0);
if (ret != SPI_OK_UTILITY) {
elog(INFO, "SPI_execexecute error: fail to set attribute to grp_name.");
SPI_finish();
return PointerGetDatum(rettuple);
}
/* add primary key to perm_member */
ret = SPI_exec("ALTER TABLE perm_member ADDPRIMARY KEY (user_name, grp_name);", 0);
if (ret != SPI_OK_UTILITY) {
elog(INFO, "SPI_execexecute error: fail to add primary key to perm_member.");
SPI_finish();
returnPointerGetDatum(rettuple);
}
}
/*close connect with SPI manager */
SPI_finish();
/* return back must be NULL*/
return PointerGetDatum(rettuple);
}
这个函数写法与postgresql服务端函数的写法很相似, 但是不完全相同.具体需要注意的地方是:
1. 需要多添加头文件:#include commands/trigger.h
2. 这个函数的返回值一定是trigger类型的.
3. 函数的开始最好确认这个函数是供触发器调用的并且明确一下自己要写的触发器的类型是什么,然后做一下判断,以免别的语句也触发的触发器.
二. 接下来的事情是编译:
gcc -fpic -c trigger.c-I/usr/local/postgreSQL/include/postgresql/server
gcc -shared -o trigger.so trigger.o
如果不明白可以参考手册(说句题外话,手册的作用实在是太大了,在手册中也提供了一例子).
三. 在数据库中创建函数和触发器:
/* create a trigger used to write memory and configmemory */
CREATE OR REPLACE FUNCTION pg_trigf() RETURNS trigger
AS 'filename'
LANGUAGE C IMMUTABLESTRICT;
CREATE TRIGGER tbuser BEFORE INSERT OR UPDATE OR DELETE
ON tbl_user FOR EACH STATEMENT
EXECUTE PROCEDURE pg_trigf();
CREATE TRIGGER tbgroup BEFORE INSERT OR UPDATE OR DELETE
创建的触发器是语句触发器,这个和手册上的不一样, 手册上的是行触发器.
然后在数据库中使用SQL语句就可以看到触发器的效果了.
Navicat for PostgreSQL 触发器常规属性:
限制:勾选此项,创建一个限制触发器。
触发器类型:可供选择的触发器类型有 Table 或 View。需要注意的是,适用于PostgreSQL 9.0 或以上版本。
表名或视图名:选择表或视图。
BEFORE:当尝试在行操作前,可以指定触发触发器。
AFTER:当尝试在行操作后,可以指定触发触发器。
INSTEAD OF:指定触发触发器来代替尝试在行操作。
INSERT/UPDATE/DELETE:选择激活触发器的事件。
插入:每当一个新行插入表,触发器会被激活。
更新:每当修改一个行,触发器会被激活。
删除:每当从表删除一个行,触发器会被激活。
TRUNCATE:触发器定义为触发 TRUNCATE。
更新栏位:指定一个列列表。如果至少一个列在 UPDATE 命令提及为目标,触发器将会触发。
STATEMENT:指定触发器过程在每个 SQL 语句触发一次。
ROW:指定触发器过程在触发器事件影响一行时触发一次。
当:指定一个布林值 WHEN 条件,测试触发器是否应该被触发,该功能支持 PostgreSQL 9.0 或以上版本。
触发函数模式和触发函数:用户提供的函数,被声明为没有引数及返回类型触发器,当触发器触发时运行。
函数引数:一个当触发器运行时,指供给函数的可选逗号分隔引数列表,引数是文本字符串常数。简单的名和数字常数可以写在这里,但它们都将被转换为字符串。请检查触发函数的实施语言描述,关于如何可访问触发器引数,它可能和正常函数引数不同。
Navicat for PostgreSQL 触发器限制:
可搁置:可搁置限制。
最初立即:在每个语句后检查限制。
最初搁置:只在事务结束时检查限制。
参考表模式和参考表名:限制参考表的模式和名。
您好,参考故障现象
使用Windows Vista系统,恢复自行备份后,出现“User Profile Service服务未能登录,无法加载用户配置文件”如下图:
?
原因分析
User Profile Service服务负责加载和卸载用户配置文件。如果已停止或禁用此服务,用户将无法再成功登录或注销,应用程序在获取用户数据时可能会出问题,而且为接收配置文件事件通知注册的组件将无法接收这些通知。出现此类问题有可能是该服务被禁用,通过进入安全模式将该服务设置为启动,即可解决。
解决方案
一、开启此服务
1、重新启动计算机开机时连续点击F8,选择进入安全模式。
2、开始-在搜索栏中输入services.msc /s(如图)
?
弹出用户帐户控制对话框后选择同意,进入本地服务设置,找到User Profile Service服务(如图)
?
双击出现属性对话框,将启动类型设置为自动(如图)
?
确定后重新启动计算机。
二、如果上述操作无效的情况下,可以执行以下操作:
1、按F8进入安全模式。
2、重新添加一个用户帐户,
postgreSQL是一款先进的开源数据库,拥有非常齐全的自由软件的对象-关系型数据库管理系统(ORDBMS),可面向企业复杂SQL的OLTP业务场景,支持多项企业级功能,能解决使用数据库的各种难题。
PostgreSQL的优势有很多。它是一个免费的对象-关系数据库服务器(ORDBMS),在灵活的BSD许可证下发行。
postgreSQL的特征
函数:通过函数,可以在数据库服务器端执行指令程序。
索引:用户可以自定义索引方法,或使用内置的 B 树,哈希表与 GiST 索引。
触发器:触发器是由SQL语句查询所触发的事件。如:一个INSERT语句可能触发一个检查数据完整性的触发器。触发器通常由INSERT或UPDATE语句触发。 多版本并发控制:PostgreSQL使用多版本并发控制(MVCC,Multiversion concurrency control)系统进行并发控制,该系统向每个用户提供了一个数据库的"快照",用户在事务内所作的每个修改,对于其他的用户都不可见,直到该事务成功提交。
规则:规则(RULE)允许一个查询能被重写,通常用来实现对视图(VIEW)的操作,如插入(INSERT)、更新(UPDATE)、删除(DELETE)。
数据类型:包括文本、任意精度的数值数组、JSON 数据、枚举类型、XML 数据等。全文检索:通过 Tsearch2 或 OpenFTS,8.3版本中内嵌 Tsearch2。
NoSQL:JSON,JSONB,XML,HStore 原生支持,至 NoSQL 数据库的外部数据包装器。
数据仓库:能平滑迁移至同属postgreSQL生态的GreenPlum,DeepGreen,HAWK 等,使用 FDW 进行 ETL。
初步认为是传入的事件类型参数不匹配,定义可以用timestamp,传入时直接用字符串,比如:'2012-8-8 00:00:00'
now()返回的是timestamp类型,所以问题出在now()这里
最好的解决办法就是函数定义的date参数改为timestamp
希望对你有所帮助