1. 做個奇怪的東西-Golang快速實現功能、c封裝成PostgreSQL的擴展:
  2. 寧衛通信
  3. 新聞動態
  4. 寧衛新聞
  5. 做個奇怪的東西-Golang快速實現功能、c封裝成PostgreSQL的擴展

做個奇怪的東西-Golang快速實現功能、c封裝成PostgreSQL的擴展

前言

       以前寫過很多數據庫方面的存儲過程之類的,應該算是小型公司的一種全棧要求,什么都要會,最多的話一個系統寫了一兩百個函數或存儲過程。最近因為在改系統,想起來以前的區號和工作時間等,都是純sql或者在開發語言層面干掉了,那么不如寫成PostgreSQL的function,本來應該這樣,但是由于以前的改動大,要多棧真的腦子變來變去,就不了了之。

操作

       首先看下以下兩個表結構: 
   用途是將基本的手機號段和區號以及省市信息記錄到nway_base_mobile_location表中;在nway_area_plan中,定義這條規則所要使用到的區號列表,用于和nway_base_mobile_location中的district_no匹配。


  1. CREATE TABLE IF NOT EXISTS public.nway_base_mobile_location

  2. (

  3. no character varying(7) COLLATE pg_catalog."default" NOT NULL,

  4. location character varying(50) COLLATE pg_catalog."default",

  5. district_no character varying(100) COLLATE pg_catalog."default"

  6. )

  7. WITH (

  8. OIDS = FALSE

  9. )

  10. TABLESPACE pg_default;


  11. ALTER TABLE IF EXISTS public.nway_base_mobile_location

  12. OWNER to postgres;


  13. COMMENT ON TABLE public.nway_base_mobile_location

  14. IS '上海寧衛信息技術有限公司,李浩。手機歸屬地';


  15. COMMENT ON COLUMN public.nway_base_mobile_location.no

  16. IS '手機號段';


  17. COMMENT ON COLUMN public.nway_base_mobile_location.location

  18. IS '所在地';


  19. COMMENT ON COLUMN public.nway_base_mobile_location.district_no

  20. IS '區號';

  21. -- Index: PK_NO_BASE_MOBILE_LOCATION


  22. -- DROP INDEX IF EXISTS public."PK_NO_BASE_MOBILE_LOCATION";


  23. CREATE INDEX IF NOT EXISTS "PK_NO_BASE_MOBILE_LOCATION"

  24. ON public.nway_base_mobile_location USING btree

  25. (no COLLATE pg_catalog."C" varchar_ops ASC NULLS LAST)

  26. TABLESPACE pg_default;

  27. -- Index: base_mobile_location_district_no


  28. -- DROP INDEX IF EXISTS public.base_mobile_location_district_no;


  29. CREATE INDEX IF NOT EXISTS base_mobile_location_district_no

  30. ON public.nway_base_mobile_location USING btree

  31. (district_no COLLATE pg_catalog."default" ASC NULLS LAST)

  32. TABLESPACE pg_default;

  33. -- Index: base_mobile_location_no


  34. -- DROP INDEX IF EXISTS public.base_mobile_location_no;


  35. CREATE INDEX IF NOT EXISTS base_mobile_location_no

  36. ON public.nway_base_mobile_location USING btree

  37. (no COLLATE pg_catalog."default" ASC NULLS LAST)

  38. TABLESPACE pg_default;


  39. ------------------------------------------------------------------------------

  40. CREATE TABLE IF NOT EXISTS public.nway_area_plan

  41. (

  42. id bigint NOT NULL DEFAULT nextval('nway_area_plan_id_seq'::regclass),

  43. plan_name character varying(100) COLLATE pg_catalog."default" NOT NULL DEFAULT ''::character varying,

  44. plan_desc text COLLATE pg_catalog."default",

  45. node_id bigint,

  46. district_no text COLLATE pg_catalog."default" DEFAULT ''::text,

  47. CONSTRAINT nway_area_plan_pkey PRIMARY KEY (id)

  48. )

  49. WITH (

  50. OIDS = FALSE

  51. )

  52. TABLESPACE pg_default;


  53. ALTER TABLE IF EXISTS public.nway_area_plan

  54. OWNER to postgres;


  55. COMMENT ON TABLE public.nway_area_plan

  56. IS '區域策略';


  57. COMMENT ON COLUMN public.nway_area_plan.district_no

  58. IS '電話區號列表';

以前的做法是使用Python或golang寫個獨立的應用,進行把xls等手機號段表單獨運行導入,不過前幾天看到 https://zhmin.github.io/ 上的一篇《Postgresql 編寫自定義 C 函數》,于是就想是不是寫成一個PostgreSQL擴展會好玩些,但是面臨的問題也比較現實:1. c語言的運算部分,代碼寫起來費勁;2. c語言在各類擴展中質量參差不齊,容易陷入調試死胡同;3. c語言各類應用的庫都不如GO、python等相對完備。所以采用Go開發成動靜態庫,再用c簡單調用一層,生成對應的PostgreSQL擴展動態庫(由Go語言直接生成也可以,不過那要折騰,還不如直接c包一層)。

代碼

將開發的Go的庫通過 
go build --ldflags "-s -w" -buildmode=c-shared -o libImptFile.so main.go 
生成so及頭文件

  1. //libImptFile.h

  2. //有一堆的定義等略過

  3. #ifdef __cplusplus

  4. extern "C" {

  5. #endif


  6. //入參

  7. //dbstring:數據庫連接字符串

  8. //file_path:本地的xsls或xls等excel表

  9. //no_idx:號段字段在excel表格中的第幾列

  10. //location_idx:位置字段在excel表格中的第幾列

  11. //district_no_idx:區號字段在excel表格中的第幾列

  12. //err_msg:錯誤時返回的字符串說明,不超過256長度

  13. //返回值

  14. //整型:0完成;-1文件不存在;-2文件格式讀取不出;1寫入庫中時異常

  15. extern int ImportMobLocFromFile(GoString dbstring, GoString file_path, GoInt no_idx, GoInt location_idx, GoInt district_no_idx, char* err_msg);


  16. #ifdef __cplusplus

  17. }

  18. #endif

然后再用c來調用

  1. #include "libImptFile.h"


  2. #include "postgres.h"

  3. #include "fmgr.h"


  4. PG_MODULE_MAGIC;


  5. PG_FUNCTION_INFO_V1(impt_file_func);

  6. Datum impt_file_func(PG_FUNCTION_ARGS)

  7. {

  8. char* dbstr=PG_GETARG_CSTRING(0);

  9. char* fp = PG_GETARG_CSTRING(1);


  10. int32 n = PG_GETARG_INT32(2);

  11. int32 l = PG_GETARG_INT32(3);

  12. int32 d = PG_GETARG_INT32(4);


  13. char* err_msg=(char*) palloc(256);

  14. //需要加個套,Gostring和GoInt

  15. int32 r=0;

  16. GoString dbstring={dbstr,strlen(dbstr)};

  17. GoString file_path={fp,strlen(fp)};

  18. GoInt no_idx=(GoInt)n;

  19. GoInt location_idx = (GoInt)l;

  20. GoInt district_no_idx=(GoInt)d;

  21. r = ImportMobLocFromFile(dbstring,file_path,no_idx,location_idx,district_no_idx,err_msg);

  22. if (r!=0){

  23. printf("call ImportMobLocFromFile failed:%s",err_msg );


  24. }

  25. pfree(err_msg);

  26. PG_RETURN_INT32(r);

  27. }

再然后編譯后調用

  1. gcc -fPIC -c impt_file_func.c -I/usr/include/pgsql/server/ -shared -o impt_file_func.so

接著在psql中

  1. CREATE FUNCTION impt_file_func(TEXT,TEXT,integer,integer,integer) RETURNS integer

  2. AS '/var/lib/11/pgsql/impt_file_func.so', 'impt_file_func' LANGUAGE C STRICT;

OK,那么就去調用吧

  1. select impt_file_func("user=postgres dbname=cloudcc password=Nway2017 host=127.0.0.1 port=5432 sslmode=disable","/home/20221011.xlsx",0,1,2) as nway_result;



台湾佬?偷拍?娱乐?中文网