#include "postgres.h"
#include "fmgr.h"
#include <string.h> #ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif #ifndef SET_VARSIZE
#define SET_VARSIZE(v,l) (VARATT_SIZEP(v) = (l))
#endif Datum hello( PG_FUNCTION_ARGS ); PG_FUNCTION_INFO_V1( hello );
Datum
hello( PG_FUNCTION_ARGS )
{
// variable declarations
char greet[] = "Hello, ";
text *towhom;
int greetlen;
int towhomlen;
text *greeting; // Get arguments. If we declare our function as STRICT, then
// this check is superfluous.
if( PG_ARGISNULL() ) {
PG_RETURN_NULL();
}
towhom = PG_GETARG_TEXT_P(); // Calculate string sizes.
greetlen = strlen(greet); /*
struct varlena
{
int32 vl_len;
char vl_dat[1];
};
*/
// VARSIZE 宏告诉我们"towhom"文本的总大小。 VARHDRSZ 宏是一个常量,它表示 varlena 结构的vl_len成员消耗的开销。
// 因此, VARSIZE (towhom)-VARHDRSZ为我们提供了文本字符串中八位位组的数量。
towhomlen = VARSIZE(towhom) - VARHDRSZ; // Allocate memory and set data structure size.
greeting = (text *)palloc( greetlen + towhomlen );
// 我们使用 VARATT_SIZEP 宏将“greeting”文本的vl_len成员设置为等于要存储的文本字符串的大小。
VARATT_SIZEP( greeting ) = greetlen + towhomlen + VARHDRSZ; // Construct greeting string.
// varlena 数据结构消除了对字符串定界符结尾的需要。 VARDATA 宏返回一个指向“ greeting”字符串的数据成员的指针。
strncpy( VARDATA(greeting), greet, greetlen );
strncpy( VARDATA(greeting) + greetlen,
VARDATA(towhom),
towhomlen ); PG_RETURN_TEXT_P( greeting );
} CREATE OR REPLACE FUNCTION
hello( TEXT )
RETURNS
TEXT
AS
'example.so', 'hello'
LANGUAGE
C
STRICT
IMMUTABLE; Open a database with the PostgreSQL interactive command line editor 'psql' as a user with permission to create new functions (i.e. superuser). Create your new 'hello' function by loading the example.sql code above. For example: prompt> \i example.sql
CREATE FUNCTION => CREATE TEMP TABLE test( name ) AS
-> VALUES ('Xavier'), ('Yari'), ('Zack'); => SELECT hello( name ) FROM test;
hello
--------------
Hello, Xavier
Hello, Yari
Hello, Zack // #include "postgres.h"
#include "fmgr.h"
#include "utils/date.h"
#include "utils/nabstime.h" #ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif PG_FUNCTION_INFO_V1 (dateserial); Datum dateserial (PG_FUNCTION_ARGS)
{
int32 year = PG_GETARG_INT32();
int32 month = PG_GETARG_INT32();
int32 day = PG_GETARG_INT32(); DateADT d = date2j (year, month, day) - POSTGRES_EPOCH_JDATE;
PG_RETURN_DATEADT(d);
} CREATE FUNCTION datefunc(int, int, int) RETURNS date AS '/usr/local/postgresql/share/extension/datefunc.so', 'dateserial' LANGUAGE C STRICT IMMUTABLE; #include "postgres.h"
#include "fmgr.h"
#include <string.h>
#include "utils/geo_decls.h" #ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif #ifndef SET_VARSIZE
#define SET_VARSIZE(v,l) (VARATT_SIZEP(v) = (l))
#endif PG_FUNCTION_INFO_V1( hello );
Datum
hello(PG_FUNCTION_ARGS)
{
text *arg1 = PG_GETARG_TEXT_PP();
text *arg2 = PG_GETARG_TEXT_PP();
int32 arg1_size = VARSIZE_ANY_EXHDR(arg1);
int32 arg2_size = VARSIZE_ANY_EXHDR(arg2);
int32 new_text_size = arg1_size + arg2_size + VARHDRSZ;
text *new_text = (text *) palloc(new_text_size);
SET_VARSIZE(new_text, new_text_size);
memcpy(VARDATA(new_text), VARDATA_ANY(arg1), arg1_size);
memcpy(VARDATA(new_text) + arg1_size, VARDATA_ANY(arg2), arg2_size);
PG_RETURN_TEXT_P(new_text);
} CREATE OR REPLACE FUNCTION
hello( TEXT )
RETURNS
TEXT
AS
'/usr/local/postgresql/share/extension/example.so', 'hello'
LANGUAGE
C
STRICT
IMMUTABLE; #include "postgres.h"
#include "executor/executor.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(coverpaid);
Datum
c_overpaid(PG_FUNCTION_ARGS)
{
/* #define PG_GETARG_HEAPTUPLEHEADER(n) DatumGetHeapTupleHeader(PG_GETARG_DATUM(n)) */
HeapTupleHeader t = PG_GETARG_HEAPTUPLEHEADER(); /* HeapTupleHeader t_data; -> tuple header and data */
int32 limit = PG_GETARG_INT32();
bool isnull;
Datum salary;
salary = GetAttributeByName(t, "salary", &isnull);
if (isnull)
PG_RETURN_BOOL(false);
PG_RETURN_BOOL(DatumGetInt32(salary) < limit);
} /* we read our tuple arguments in to rt and lt, using the PG_GETARG_HEAPTUPLEHEADER macro.
使用 PG_GETARG_HEAPTUPLEHEADER 宏将我们的元组参数读入rt和lt中。 GetAttributeByName 是返回指定行的属性的PostgreSQL系统函数。它有三个参数:类型为HeapTupleHeader的传入参数、
想要访问的函数名以及一个说明该属性是否为空的返回参数。
GetAttributeByName返回一个Datum值,可以把它用合适的DatumGetXXX() 宏转换成正确的数据类型。
注意如果空值标志被设置,那么返回值是没有意义的,所以在对结果做任何事情之前应该先检查空值标志。 */ CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean
AS '/usr/local/postgresql/share/extension/c_overpaid.so', 'c_overpaid'
LANGUAGE C STRICT; -- PostgreSQL › PostgreSQL - interfaces
Login Register
help needed on SPI_modifytuple.
‹ Previous Topic Next Topic › classic Classic list List threaded Threaded
messages Options Options
fabrizio picca
Reply | Threaded | More
Selected post Sep , ; :17pm
help needed on SPI_modifytuple.
fabrizio picca
posts I'm trying to sipmply modify a tuple before it will be inserted in the db.
The problem is that when it try to insert the modified tuple with
SPI_modifytuple all i get is a SPI_ERROR_ARGUMENT negative (-) .
Could someone help me? i'm reallygoing crazy. What i did is just a fire-before C trigger that acts like this: #include <postgres.h>
#include <executor/spi.h> /* this is what you need to work with SPI */
#include <commands/trigger.h> /* ... and triggers */
#include <string.h>
#include <utils/builtins.h> extern Datum trgupdana(PG_FUNCTION_ARGS);
char *checkFieldData(char *); PG_FUNCTION_INFO_V1(trgupdana); Datum
trgupdana(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
TupleDesc tupdesc;
HeapTuple rettuple,
oldtuple,
newtuple;
char *rs1,*rs2,*rs3,*relname;
int ret, i,j;
bool isnull;
Relation rel; /* make sure it's called as a trigger at all */
if (!CALLED_AS_TRIGGER(fcinfo)) elog(ERROR, "trgchkneg: not called
by trigger manager\n"); if (TRIGGER_FIRED_BEFORE(trigdata->tg_event) &&
TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) //trigger fires when called
for rows and before updating
{
tupdesc = trigdata->tg_relation->rd_att;
oldtuple = trigdata->tg_trigtuple;
newtuple = trigdata->tg_newtuple;
rettuple=NULL;
rel = trigdata->tg_relation;
relname= SPI_getrelname(rel); if ((ret = SPI_connect()) < ) // SPI
manager initialization
elog(NOTICE, "trgCheckNeg : SPI_connect returned: %d", ret); rs1=SPI_getvalue(oldtuple,tupdesc,);
rs2=SPI_getvalue(oldtuple,tupdesc,); elog(NOTICE,"%s,%s",rs1,rs2); int attnum;
Datum new_value; rs3=(char*) malloc();
sprintf(rs3,""); if(rs1[strlen(rs1)-]=='&'){
rs3=strncat(rs3,rs1,strlen(rs1)-);
rs3=strcat(rs3,"E ");
}
else if(rs1[strlen(rs1)-]==',')
{
rs3=strncat(rs3,rs1,strlen(rs1)-);
rs3=strcat(rs3,", ");
} else {
rs3=rs1;
} elog(NOTICE,"1:%s",rs3); if(strlen(rs2)!=){
rs3=strcat(rs3,rs2);
} elog(NOTICE,"2:%s",rs3); new_value=DirectFunctionCall1(textin,PointerGetDatum(checkFieldData(rs3))); attnum=SPI_fnumber(tupdesc,"ARGSL1"); if(rel==NULL) elog(NOTICE,"rel NULL");
if(&attnum==NULL) elog(NOTICE,"attnum NULL");
if(&new_value==NULL) elog(NOTICE,"new_value NULL");
if(&isnull==NULL) elog(NOTICE,"isnull NULL"); rettuple=SPI_modifytuple(rel,newtuple,,&attnum,&new_value,&isnull);
if(rettuple==NULL){
elog(ERROR,"trgupdana (%s):%d returned by SPI_modifytuple",relname,SPI_result);
}
return PointerGetDatum(rettuple);
}
return PointerGetDatum(oldtuple);
} char *checkFieldData(char *valueToCheck){
int i=;
for(i=;i<strlen(valueToCheck);i++)
{
if(valueToCheck[i]=='&') valueToCheck[i]='E';
else if(valueToCheck[i]=='\'') valueToCheck[i]=;
} return(valueToCheck);
} --
http://www.fabpicca.net ---------------------------(end of broadcast)---------------------------
TIP : don't forget to increase your free space map settings
Michael Fuhr
Reply | Threaded | More
Sep , ; :36am
Re: help needed on SPI_modifytuple.
Michael Fuhr
posts On Mon, Sep , at ::33PM +, fabrizio picca wrote:
> I'm trying to sipmply modify a tuple before it will be inserted in the db. > The problem is that when it try to insert the modified tuple with
> SPI_modifytuple all i get is a SPI_ERROR_ARGUMENT negative (-) .
> Could someone help me? i'm reallygoing crazy.
>
> What i did is just a fire-before C trigger that acts like this: Is the trigger fired on INSERT, UPDATE, or both? > oldtuple = trigdata->tg_trigtuple;
> newtuple = trigdata->tg_newtuple;
[...]
> rettuple=SPI_modifytuple(rel,newtuple,,&attnum,&new_value,&isnull); I didn't look closely at the rest of the code, but if the trigger
is fired on INSERT then you should pass oldtuple; newtuple will be NULL, causing SPI_modifytuple() to fail with SPI_ERROR_ARGUMENT.
Here's an extract from "Writing Trigger Functions in C" in the
"Triggers" chapter of the documentation: tg_trigtuple A pointer to the row for which the trigger was fired. This is
the row being inserted, updated, or deleted. If this trigger was
fired for an INSERT or DELETE then this is what you should return
from the function if you don't want to replace the row with a
different one (in the case of INSERT) or skip the operation. tg_newtuple A pointer to the new version of the row, if the trigger was fired
for an UPDATE, and NULL if it is for an INSERT or a DELETE. This is what you have to return from the function if the event is an
UPDATE and you don't want to replace this row by a different one
or skip the operation. --
Michael Fuhr ---------------------------(end of broadcast)---------------------------
TIP : Have you checked our extensive FAQ? http://www.postgresql.org/docs/faq
fabrizio picca
Reply | Threaded | More
Sep , ; :01am
Re: help needed on SPI_modifytuple.
fabrizio picca
posts thanks a lot Michael, you've just hit the problem!
Now everything works fine! Thanks again
Fabrizio On //, Michael Fuhr <[hidden email]> wrote: > On Mon, Sep , at ::33PM +, fabrizio picca wrote:
> > I'm trying to sipmply modify a tuple before it will be inserted in the db.
> > The problem is that when it try to insert the modified tuple with
> > SPI_modifytuple all i get is a SPI_ERROR_ARGUMENT negative (-) .
> > Could someone help me? i'm reallygoing crazy.
> >
> > What i did is just a fire-before C trigger that acts like this:
>
> Is the trigger fired on INSERT, UPDATE, or both?
>
> > oldtuple = trigdata->tg_trigtuple;
> > newtuple = trigdata->tg_newtuple;
> [...]
> > rettuple=SPI_modifytuple(rel,newtuple,,&attnum,&new_value,&isnull);
>
> I didn't look closely at the rest of the code, but if the trigger
> is fired on INSERT then you should pass oldtuple; newtuple will be
> NULL, causing SPI_modifytuple() to fail with SPI_ERROR_ARGUMENT.
> Here's an extract from "Writing Trigger Functions in C" in the
> "Triggers" chapter of the documentation:
>
> tg_trigtuple
>
> A pointer to the row for which the trigger was fired. This is
> the row being inserted, updated, or deleted. If this trigger was
> fired for an INSERT or DELETE then this is what you should return
> from the function if you don't want to replace the row with a
> different one (in the case of INSERT) or skip the operation.
>
> tg_newtuple
>
> A pointer to the new version of the row, if the trigger was fired
> for an UPDATE, and NULL if it is for an INSERT or a DELETE. This
> is what you have to return from the function if the event is an
> UPDATE and you don't want to replace this row by a different one
> or skip the operation.
>
> --
> Michael Fuhr
>
... [show rest of quote] --
L'Estetica del lavoro è lo spettacolo della merce umana (Area)
--
http://www.fabpicca.net ---------------------------(end of broadcast)---------------------------
TIP : In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match
« Return to PostgreSQL - interfaces | views
Free forum by Nabble Disable Ads | Edit this page --- SPI_getrelname SPI_modifytuple
SPI_modifytuple — 通过替换一个给定行的选定域来创建一行
大纲
HeapTuple SPI_modifytuple(Relation rel, HeapTuple row, int ncols,
int * colnum, Datum * values, const char * nulls)
描述
SPI_modifytuple创建一个新行,其中选定的列 用新值替代,其他列则从输入行中拷贝。输入
行本身不被修改。 新行在上层执行器上下文中返回。
该函数只能在连接到SPI时使用。否则,它会返回NULL并将SPI_result 设置
为SPI_ERROR_UNCONNECTED。
参数
Relation rel
只被用作该行的行描述符的来源(传递一个关系而不是 一个行描述符是一种令人头痛的
设计)。
HeapTuple row
要被修改的行
int ncols
要被修改的列数
int * colnum
一个长度为ncols的数组,包含了要被修改的列号 (列号从 开始)
Datum * values
一个长度为ncols的数组,包含了指定列的新值
const char * nulls
一个长度为ncols的数组,描述哪些新值为空值
如果nulls为NULL,那么 SPI_modifytuple假定没有新值为空值。否则, 如果对应的新值
为非空,nulls数组的每一项都应 该是' ',而如果对应的新值为空值则为'n'(在 后一种情
况中,对应的values项中的新值无关紧 要)。注意nulls不是一个文本字符串,只是一个
数组:它不需要一个'\0'终止符。
返回值
应用了修改的新行,在上层执行器上下文中分配,或者错误时为 NULL(参阅SPI_result获取
错误指示)
出错时,SPI_result被设置如下:
SPI_ERROR_ARGUMENT
如果rel为NULL,或者 row为NULL,或者ncols 小于等于 ,或者colnum为NULL, 或 者values为NULL。 SPI_ERROR_NOATTRIBUTE
如果colnum包含一个无效的列号(小于等于 或者大于 row中的列数)。
SPI_ERROR_UNCONNECTED
如果SPI未激活 -- Before we begin, let's look at what we want to accomplish. Let's say we'd like to create a set of PostgreSQL functions that implement the features of Mark Galassi's excellent GNU Scientific Library. Let's pick one of the library's functions, gsl_complex_add, and see what we need to do to create a corresponding PostgreSQL function. When we're finished, we'll be able to write SQL statements like this: > select gsl_complex_add( ROW( 3.2e4, -3.2 ), ROW( 4.1, 4.245e-3 ) ); gsl_complex_add
---------------------
(32004.1,-3.195755) I think it's appropriate to represent complex numbers in PostgreSQL as tuples, where the real and imaginary components get passed around together as a pair. Think of a tuple as a structure in C. The tuple concept jibes with the way we're taught to think about these things in other domains. We'll be using PostgreSQL's CREATE TYPE statement to define the composite type we use as follows: DROP FUNCTION gsl_complex_add ( __complex, __complex );
DROP TYPE __complex; CREATE TYPE __complex AS ( r float, i float ); CREATE OR REPLACE FUNCTION
gsl_complex_add( __complex, __complex )
RETURNS
__complex
AS
'example.so', 'c_complex_add'
LANGUAGE
C
STRICT // PostgreSQL includes
#include "postgres.h"
#include "fmgr.h"
// Tuple building functions and macros
#include "access/heapam.h"
#include "funcapi.h" #include <string.h> // GNU Scientific Library headers
#include <gsl/gsl_complex.h>
#include <gsl/gsl_complex_math.h> #ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif // forward declaration to keep compiler happy
Datum c_complex_add( PG_FUNCTION_ARGS ); PG_FUNCTION_INFO_V1( c_complex_add );
Datum
c_complex_add( PG_FUNCTION_ARGS )
{
// input variables
HeapTupleHeader lt, rt; bool isNull;
int tuplen;
bool *nulls; // things we need to deal with constructing our composite type
TupleDesc tupdesc; /* 行描述符 */
Datum values[];
HeapTuple tuple; // See PostgreSQL Manual section 33.9.2 for base types in C language
// functions, which tells us that our sql 'float' (aka 'double
// precision') is a 'float8 *' in PostgreSQL C code.
float8 *tmp; // defined by GSL library
gsl_complex l, r, ret; // Get arguments. If we declare our function as STRICT, then
// this check is superfluous.
if( PG_ARGISNULL() ||
PG_ARGISNULL() )
{
PG_RETURN_NULL();
} /*
首先,我们使用 PG_GETARG_HEAPTUPLEHEADER 宏读取rt和lt中的元组参数。
然后,使用 GetAttributeByNum 函数从元组中选择组件值。
*/
// Get components of first complex number
//// get the tuple
lt = PG_GETARG_HEAPTUPLEHEADER();
////// get the first element of the tuple
tmp = (float8*)GetAttributeByNum( lt, , &isNull );
if( isNull ) { PG_RETURN_NULL(); }
GSL_SET_REAL( &l, *tmp );
////// get the second element of the tuple
tmp = (float8*)GetAttributeByNum( lt, , &isNull );
if( isNull ) { PG_RETURN_NULL(); }
GSL_SET_IMAG( &l, *tmp ); // Get components of second complex number
rt = PG_GETARG_HEAPTUPLEHEADER();
tmp = (float8*)GetAttributeByNum( rt, , &isNull );
if( isNull ) { PG_RETURN_NULL(); }
GSL_SET_REAL( &r, *tmp );
tmp = (float8*)GetAttributeByNum( rt, , &isNull );
if( isNull ) { PG_RETURN_NULL(); }
GSL_SET_IMAG( &r, *tmp ); // Example of how to print informational debugging statements from
// your PostgreSQL module. Remember to set minimum log error
// levels appropriately in postgresql.conf, or you might not
// see any output.
ereport( INFO,
( errcode( ERRCODE_SUCCESSFUL_COMPLETION ),
errmsg( "tmp: %e\n", *tmp ))); // call our GSL library function
ret = gsl_complex_add( l, r ); // Now we need to convert this value into a PostgreSQL composite type. /* 为结果类型构造一个元组描述符 */
if( get_call_result_type( fcinfo, NULL, &tupdesc ) != TYPEFUNC_COMPOSITE ) // fcinfo: "fmgr.h" Postgres函数管理器和函数调用接口的定义。
//该文件必须包含在所有定义或调用fmgr-callable函数的Postgres模块中。
// get_call_result_type: funcapi.c fmgr函数的实用程序和便捷函数,这些函数返回集和/或复合类型,或处理VARIADIC输入。
ereport( ERROR,
( errcode( ERRCODE_FEATURE_NOT_SUPPORTED ),
errmsg( "function returning record called in context "
"that cannot accept type record" ))); // Use BlessTupleDesc if working with Datums. Use
// TupleDescGetAttInMetadata if working with C strings (official
// 8.2 docs section 33.9.9 shows usage)
/*
在处 理 Datum 时,需要把该TupleDesc传递给 BlessTupleDesc,
接着为每一行调用 heap_form_tuple
*/
BlessTupleDesc( tupdesc ); // WARNING: Architecture specific code!
// GSL uses double representation of complex numbers, which
// on x86 is 8 bytes.
// Float8GetDatum defined in postgres.h.
values[] = Float8GetDatum( GSL_REAL( ret ) ); // 通过使用Float8GetDatum函数,我们会将GSL可以理解的数据转换回PostgreSQL可以理解的格式。
values[] = Float8GetDatum( GSL_IMAG( ret ) ); tuplen = tupdesc->natts; /* number of attributes in the tuple */
nulls = palloc( tuplen * sizeof( bool ) ); // build tuple from datum array
tuple = heap_form_tuple( tupdesc, values, nulls ); pfree( nulls ); // A float8 datum palloc's space, so if we free them too soon,
// their values will be corrupted (so don't pfree here, let
// PostgreSQL take care of it.)
// pfree(values); PG_RETURN_DATUM( HeapTupleGetDatum( tuple ) );
} 在我看到 HeapTupleHeader 变量lt和rt的声明(对于“ left tuple”和“ right tuple”)之前,
相对于我的上一篇文章,这里没有太多新的事情。
在这里,我们不将简单的数据类型作为参数,
正在使用我们在CREATE TYPE语句中定义的元组参数。
我们的每个元组都有两个双精度分量,
分别表示复数的实数和虚数分量。 这些函数从给定的元组Datum中返回请求的属性的值。
以元组为参数的C函数应该使用它们。 例如:overpaid(EMP)可能会调用 GetAttributeByNum ()。
注意:这些实际上很慢,因为它们在每次调用时都会进行 typcache 查找。 GetAttributeByName 是返回指定行的属性的 PostgreSQL系统函数。它有三个参数: 类型
为HeapTupleHeader的传入参数、想要访问的函数名 以及一个说明该属性是否为空的返回参
数。 GetAttributeByName 返回一个Datum 值,可以把它用合适的DatumGetXXX() 宏转换成正
确的数据类型。注意如果空值标志被设置,那么返回值是没有 意义的,所以在对结果做任何
事情之前应该先检查空值标志。 碰巧我们的GSL库的复数函数期望输入“双”值,在我正在运行的x86 Linux平台上,
该值方便地为8个字节,并直接映射到PostgreSQL使用的float8值。 请在这里密切注意,因为如果您的数据类型映射不正确,您会头疼。 get_call_result_type:
get_call_result_type 可以解析多态函数结果的实际类型;
因此,它在返回标量多态结果的函数中很有用,
不仅是返回合成的函数。
resultTypeId输出主要用于返回多态标量的函数。
给定一个函数的调用信息记录,确定应返回的数据类型。
如果resultTypeId不为NULL,
则* resultTypeId会接收实际的数据类型OID(这主要用于标量结果类型)。
如果resultTupleDesc不为NULL,
则* resultTupleDesc会在结果为复合类型时接收到指向TupleDesc的指针,
而在其为标量结果时会接收到NULL。
检查结果是否为 TYPEFUNC_COMPOSITE ;
如果是这样,则resultTupleDesc已填充所需的TupleDesc。

postgresql spi开发笔记的更多相关文章

  1. 《ArcGIS Runtime SDK for Android开发笔记》——离在线一体化技术:概述

    1.前言 数据生产和数据展示是常见的两大专业级移动GIS应用场景,这里我们针对数据生产环节的ArcGIS的离在线一体化技术给大家做一个基本的介绍和梳理. 使用ArcGIS离在线一体化技术首先需要以下基 ...

  2. Hi3516开发笔记(一):海思HI3516DV300芯片介绍,入手开发板以及Demo测试

    前言   目前主流国产芯片为RV11XX.RK33XX.Hi35XX系列,本系列开启Hi3516系列的开发教程.   Hi3516DV300芯片介绍   Hi3516DV300为专业行Smart IP ...

  3. [开发笔记]-未找到与约束ContractName Microsoft.VisualStudio.Text.ITextDocumentFactoryService...匹配的导出【转载自:酷小孩】

    原文地址:http://www.cnblogs.com/babycool/p/3199158.html 今天打算用VisualStudio2012做一个js效果页面测试的时候,打开VS2012新建项目 ...

  4. EasyUI 开发笔记(二)

    接上篇 :EasyUI 开发笔记(一)  (http://www.cnblogs.com/yiayi/p/3485258.html) 这期就简单介绍下, easyui 的 list 展示, 在easy ...

  5. EasyUI 开发笔记(一)

    由于某些原因,在公司做的后台需要改成类似于Ext.js 形式的后台,主要看好其中的 框架布局,以及tab开页面和弹出式内部窗体. 后来看看,改成EasyUI,较Ext.js 库小很多,也便于公司的初级 ...

  6. [Openwrt 项目开发笔记]:Openwrt平台搭建(一)

    [Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 最近开始着手进行Openwrt平台的物联网网关设 ...

  7. Android移动APP开发笔记——Cordova(PhoneGap)通过CordovaPlugin插件调用 Activity 实例

    引言 Cordova(PhoneGap)采用的是HTML5+JavaScript混合模式来开发移动手机APP,因此当页面需要获取手机内部某些信息时(例如:联系人信息,坐标定位,短信等),程序就需要调用 ...

  8. Android移动APP开发笔记——最新版Cordova 5.3.1(PhoneGap)搭建开发环境

    引言 简单介绍一下Cordova的来历,Cordova的前身叫PhoneGap,自被Adobe收购后交由Apache管理,并将其核心功能开源改名为Cordova.它能让你使用HTML5轻松调用本地AP ...

  9. 开发笔记:基于EntityFramework.Extended用EF实现指定字段的更新

    今天在将一个项目中使用存储过程的遗留代码迁移至新的架构时,遇到了一个问题——如何用EF实现数据库中指定字段的更新(根据UserId更新Users表中的FaceUrl与AvatarUrl字段)? 原先调 ...

随机推荐

  1. 洛谷$P$3327 约数个数和 $[SDOI2015]$ 莫比乌斯反演

    正解:莫比乌斯反演 解题报告: 传送门! 先考虑证明一个结论,$d_{i\cdot j}=\sum_{p|i}\sum_{q|j}[gcd(p,q)==1]$ 看起来就很对的样子,但还是证下趴$QwQ ...

  2. CommandPattern(命令模式)-----Java/.Net

    命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式.请求以命令的形式包裹在对象中,并传给调用对象.调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该 ...

  3. 一次 kafka 消息堆积问题排查

    收到某业务组的小伙伴发来的反馈,具体问题如下: 项目中某 kafka 消息组消费特别慢,有时候在 kafka-manager 控制台看到有些消费者已被踢出消费组. 从服务端日志看到如下信息: 该消费组 ...

  4. 从零开始学asyncio(上)

    这篇文章主要是介绍生成器和IO多路复用机制, 算是学习asyncio需要的预备知识. 这个系列还有另外两篇文章: 从零开始学asyncio(中) 从零开始学asyncio(下) 一. 简单爬虫实例 首 ...

  5. WPF 添加提示动画

    下面放一张效果图: 那么具体是怎么实现呢: 前端XAML中: <Image Source="/Images/tips.png" HorizontalAlignment=&qu ...

  6. 解决httpclient设置代理ip之后请求无响应的问题

    httpclient这个工具类对于大家来说应该都不陌生吧,最近在使用过程中出现了碰到一个棘手的问题,当请求的接口地址由http变成https之后,程序执行到 httpClient.execute(ht ...

  7. 记录一下第一次用markdown写博客回滚过程

    前面写博客,一直用的是博客园的TinyMCE编辑器, 今天不知道哪根筋搭牢了,想试试用Markdown写. 于是在“选项”里面把默认编辑器修改为“Markdown”,鉴于本人有一定的Markdown基 ...

  8. python递归(函数)

    递归:一个过程或函数调用自身的一种方法. 1. 效果图 2. 代码 def factorial(n): ''' 该函数用来求任意数的阶乘 参数: n 要求阶乘的数字 ''' # 基线条件 判断n是否为 ...

  9. MySQL/数据库 知识点总结

    书籍推荐 <SQL基础教程(第2版)> (入门级) <高性能MySQL : 第3版> (进阶) 文字教程推荐 SQL Tutorial (SQL语句学习,英文).SQL Tut ...

  10. GitHub进阶之利用Git远程仓库篇

    #在上一篇文章,相信大家对GitHub已经有了一个基础的理解 接下来我们来学习一下如何利用git来远程仓库 一,git是什么 git:一个免费的开源版本控制软件 用途:利用Git管理GitHub上的代 ...