相比较于Mysql,postgresql可以有自定义类型,更灵活的扩展函数机制。下面的例子中将展示在数据库中新建一个地址类型。并且支持地址类型的索引,自定义比较,格式化输出。下图展示的是BNF 定义格式。一个地址应该由4 部分组成: DetailedUnitRoad, Suburb, State and Postcode,例如
U19/36 Queen Ave, Southgate, AR 7279
PG_FUNCTION_INFO_V1(postaddress_in);Datumpostaddress_in(PG_FUNCTION_ARGS){char*str=PG_GETARG_CSTRING(0);PostAddress*result;int32struct_size;char*unit="",*street="",*suburb="",*state="",*postcode="",*original;char*t=NULL;intunit_len,street_len,suburb_len,state_len,postcode_len,original_len;intlen=strlen(str);char*value=(char*)palloc(len+1);strcpy(value,str);value[len]='\0';original=value;t=strtok(str,",");if(t==NULL){ereport(ERROR,errmsg("invalid input syntax for type PostAddress: \"%s\"",original));}char*slash=strchr(t,'/');if(slash==NULL){if(!check_street(t))ereport(ERROR,errmsg("invalid input syntax for type PostAddress: \"%s\"",original));t=to_lower(t);street=t;}else{*slash='\0';if(!check_unit(t)||!check_street(slash+1))ereport(ERROR,errmsg("invalid input syntax for type PostAddress: \"%s\"",original));char*s=slash+1;t=to_lower(t);s=to_lower(s);unit=t;street=s;}t=strtok(NULL,",");if(t==NULL){ereport(ERROR,errmsg("invalid input syntax for type PostAddress: \"%s\"",original));}if(!check_suburb(t)){ereport(ERROR,errmsg("invalid input syntax for type PostAddress: \"%s\"",original));}t=to_lower(t+1);//skip space
suburb=t;t=strtok(NULL,">");if(t==NULL||t[0]!=' '){ereport(ERROR,errmsg("invalid input syntax for type PostAddress: \"%s\"",original));}t=t+1;//skip space
slash=strchr(t,' ');if(slash==NULL){ereport(ERROR,errmsg("invalid input syntax for type PostAddress: \"%s\"",original));}else{*slash='\0';if(!check_state(t)||!check_postcode(slash+1))ereport(ERROR,errmsg("invalid input syntax for type PostAddress: \"%s\"",original));char*s=slash+1;t=to_lower(t);s=to_lower(s);state=t;postcode=slash+1;}unit_len=strlen(unit);street_len=strlen(street);suburb_len=strlen(suburb);state_len=strlen(state);postcode_len=strlen(postcode);original_len=strlen(original);struct_size=(int32)(offsetof(PostAddress,data)+unit_len+street_len+suburb_len+state_len+postcode_len+original_len);result=(PostAddress*)palloc(struct_size);SET_VARSIZE(result,struct_size);result->unit_len=unit_len;result->street_len=street_len;result->suburb_len=suburb_len;result->state_len=state_len;result->postcode_len=postcode_len;result->original_len=original_len;intoffset=0;memcpy(result->data+offset,unit,unit_len);offset+=unit_len;memcpy(result->data+offset,street,street_len);offset+=street_len;memcpy(result->data+offset,suburb,suburb_len);offset+=suburb_len;memcpy(result->data+offset,state,state_len);offset+=state_len;memcpy(result->data+offset,postcode,postcode_len);offset+=postcode_len;memcpy(result->data+offset,original,original_len);offset+=postcode_len;PG_RETURN_POINTER(result);}