github.com/jackc/pgx/v5@v5.5.5/pgtype/hstore_test.go (about) 1 package pgtype_test 2 3 import ( 4 "context" 5 "fmt" 6 "reflect" 7 "testing" 8 "time" 9 10 "github.com/jackc/pgx/v5" 11 "github.com/jackc/pgx/v5/pgtype" 12 "github.com/jackc/pgx/v5/pgxtest" 13 ) 14 15 func isExpectedEqMapStringString(a any) func(any) bool { 16 return func(v any) bool { 17 am := a.(map[string]string) 18 vm := v.(map[string]string) 19 20 if len(am) != len(vm) { 21 return false 22 } 23 24 for k, v := range am { 25 if vm[k] != v { 26 return false 27 } 28 } 29 30 return true 31 } 32 } 33 34 func isExpectedEqMapStringPointerString(a any) func(any) bool { 35 return func(v any) bool { 36 am := a.(map[string]*string) 37 vm := v.(map[string]*string) 38 39 if len(am) != len(vm) { 40 return false 41 } 42 43 for k, v := range am { 44 if (vm[k] == nil) != (v == nil) { 45 return false 46 } 47 48 if v != nil && *vm[k] != *v { 49 return false 50 } 51 } 52 53 return true 54 } 55 } 56 57 // stringPtr returns a pointer to s. 58 func stringPtr(s string) *string { 59 return &s 60 } 61 62 func TestHstoreCodec(t *testing.T) { 63 ctr := defaultConnTestRunner 64 ctr.AfterConnect = func(ctx context.Context, t testing.TB, conn *pgx.Conn) { 65 var hstoreOID uint32 66 err := conn.QueryRow(context.Background(), `select oid from pg_type where typname = 'hstore'`).Scan(&hstoreOID) 67 if err != nil { 68 t.Skipf("Skipping: cannot find hstore OID") 69 } 70 71 conn.TypeMap().RegisterType(&pgtype.Type{Name: "hstore", OID: hstoreOID, Codec: pgtype.HstoreCodec{}}) 72 } 73 74 tests := []pgxtest.ValueRoundTripTest{ 75 { 76 map[string]string{}, 77 new(map[string]string), 78 isExpectedEqMapStringString(map[string]string{}), 79 }, 80 { 81 map[string]string{"foo": "", "bar": "", "baz": "123"}, 82 new(map[string]string), 83 isExpectedEqMapStringString(map[string]string{"foo": "", "bar": "", "baz": "123"}), 84 }, 85 { 86 map[string]string{"NULL": "bar"}, 87 new(map[string]string), 88 isExpectedEqMapStringString(map[string]string{"NULL": "bar"}), 89 }, 90 { 91 map[string]string{"bar": "NULL"}, 92 new(map[string]string), 93 isExpectedEqMapStringString(map[string]string{"bar": "NULL"}), 94 }, 95 { 96 map[string]string{"": "foo"}, 97 new(map[string]string), 98 isExpectedEqMapStringString(map[string]string{"": "foo"}), 99 }, 100 { 101 map[string]*string{}, 102 new(map[string]*string), 103 isExpectedEqMapStringPointerString(map[string]*string{}), 104 }, 105 { 106 map[string]*string{"foo": stringPtr("bar"), "baq": stringPtr("quz")}, 107 new(map[string]*string), 108 isExpectedEqMapStringPointerString(map[string]*string{"foo": stringPtr("bar"), "baq": stringPtr("quz")}), 109 }, 110 { 111 map[string]*string{"foo": nil, "baq": stringPtr("quz")}, 112 new(map[string]*string), 113 isExpectedEqMapStringPointerString(map[string]*string{"foo": nil, "baq": stringPtr("quz")}), 114 }, 115 {nil, new(*map[string]string), isExpectedEq((*map[string]string)(nil))}, 116 {nil, new(*map[string]*string), isExpectedEq((*map[string]*string)(nil))}, 117 {nil, new(*pgtype.Hstore), isExpectedEq((*pgtype.Hstore)(nil))}, 118 } 119 120 specialStrings := []string{ 121 `"`, 122 `'`, 123 `\`, 124 `\\`, 125 `=>`, 126 ` `, 127 `\ / / \\ => " ' " '`, 128 "line1\nline2", 129 "tab\tafter", 130 "vtab\vafter", 131 "form\\ffeed", 132 "carriage\rreturn", 133 "curly{}braces", 134 // Postgres on Mac OS X hstore parsing bug: 135 // ą = "\xc4\x85" in UTF-8; isspace(0x85) on Mac OS X returns true instead of false 136 "mac_bugą", 137 } 138 for _, s := range specialStrings { 139 // Special key values 140 141 // at beginning 142 tests = append(tests, pgxtest.ValueRoundTripTest{ 143 map[string]string{s + "foo": "bar"}, 144 new(map[string]string), 145 isExpectedEqMapStringString(map[string]string{s + "foo": "bar"}), 146 }) 147 // in middle 148 tests = append(tests, pgxtest.ValueRoundTripTest{ 149 map[string]string{"foo" + s + "bar": "bar"}, 150 new(map[string]string), 151 isExpectedEqMapStringString(map[string]string{"foo" + s + "bar": "bar"}), 152 }) 153 // at end 154 tests = append(tests, pgxtest.ValueRoundTripTest{ 155 map[string]string{"foo" + s: "bar"}, 156 new(map[string]string), 157 isExpectedEqMapStringString(map[string]string{"foo" + s: "bar"}), 158 }) 159 // is key 160 tests = append(tests, pgxtest.ValueRoundTripTest{ 161 map[string]string{s: "bar"}, 162 new(map[string]string), 163 isExpectedEqMapStringString(map[string]string{s: "bar"}), 164 }) 165 166 // Special value values 167 168 // at beginning 169 tests = append(tests, pgxtest.ValueRoundTripTest{ 170 map[string]string{"foo": s + "bar"}, 171 new(map[string]string), 172 isExpectedEqMapStringString(map[string]string{"foo": s + "bar"}), 173 }) 174 // in middle 175 tests = append(tests, pgxtest.ValueRoundTripTest{ 176 map[string]string{"foo": "foo" + s + "bar"}, 177 new(map[string]string), 178 isExpectedEqMapStringString(map[string]string{"foo": "foo" + s + "bar"}), 179 }) 180 // at end 181 tests = append(tests, pgxtest.ValueRoundTripTest{ 182 map[string]string{"foo": "foo" + s}, 183 new(map[string]string), 184 isExpectedEqMapStringString(map[string]string{"foo": "foo" + s}), 185 }) 186 // is key 187 tests = append(tests, pgxtest.ValueRoundTripTest{ 188 map[string]string{"foo": s}, 189 new(map[string]string), 190 isExpectedEqMapStringString(map[string]string{"foo": s}), 191 }) 192 } 193 194 pgxtest.RunValueRoundTripTests(context.Background(), t, ctr, pgxtest.KnownOIDQueryExecModes, "hstore", tests) 195 196 // run the tests using pgtype.Hstore as input and output types, and test all query modes 197 for i := range tests { 198 var h pgtype.Hstore 199 switch typedParam := tests[i].Param.(type) { 200 case map[string]*string: 201 h = pgtype.Hstore(typedParam) 202 case map[string]string: 203 if typedParam != nil { 204 h = pgtype.Hstore{} 205 for k, v := range typedParam { 206 h[k] = stringPtr(v) 207 } 208 } 209 } 210 211 tests[i].Param = h 212 tests[i].Result = &pgtype.Hstore{} 213 tests[i].Test = func(input any) bool { 214 return reflect.DeepEqual(input, h) 215 } 216 } 217 pgxtest.RunValueRoundTripTests(context.Background(), t, ctr, pgxtest.AllQueryExecModes, "hstore", tests) 218 219 // run the tests again without the codec registered: uses the text protocol 220 ctrWithoutCodec := defaultConnTestRunner 221 pgxtest.RunValueRoundTripTests(context.Background(), t, ctrWithoutCodec, pgxtest.AllQueryExecModes, "hstore", tests) 222 223 // scan empty and NULL: should be different in all query modes 224 ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) 225 defer cancel() 226 227 pgxtest.RunWithQueryExecModes(ctx, t, ctr, pgxtest.AllQueryExecModes, func(ctx context.Context, t testing.TB, conn *pgx.Conn) { 228 h := pgtype.Hstore{"should_be_erased": nil} 229 err := conn.QueryRow(ctx, `select cast(null as hstore)`).Scan(&h) 230 if err != nil { 231 t.Fatal(err) 232 } 233 expectedNil := pgtype.Hstore(nil) 234 if !reflect.DeepEqual(h, expectedNil) { 235 t.Errorf("plain conn.Scan failed expectedNil=%#v actual=%#v", expectedNil, h) 236 } 237 238 err = conn.QueryRow(ctx, `select cast('' as hstore)`).Scan(&h) 239 if err != nil { 240 t.Fatal(err) 241 } 242 expectedEmpty := pgtype.Hstore{} 243 if !reflect.DeepEqual(h, expectedEmpty) { 244 t.Errorf("plain conn.Scan failed expectedEmpty=%#v actual=%#v", expectedEmpty, h) 245 } 246 }) 247 } 248 249 func TestParseInvalidInputs(t *testing.T) { 250 // these inputs should be invalid, but previously were considered correct 251 invalidInputs := []string{ 252 // extra comma between values 253 `"a"=>"1", ,b"=>"2"`, 254 // missing doublequote before second value 255 `""=>"", 0"=>""`, 256 } 257 for i, input := range invalidInputs { 258 var hstore pgtype.Hstore 259 err := hstore.Scan(input) 260 if err == nil { 261 t.Errorf("test %d: input=%s (%#v) should fail; parsed correctly", i, input, input) 262 } 263 } 264 } 265 266 func TestRoundTrip(t *testing.T) { 267 codecs := []struct { 268 name string 269 encodePlan pgtype.EncodePlan 270 scanPlan pgtype.ScanPlan 271 }{ 272 { 273 "text", 274 pgtype.HstoreCodec{}.PlanEncode(nil, 0, pgtype.TextFormatCode, pgtype.Hstore(nil)), 275 pgtype.HstoreCodec{}.PlanScan(nil, 0, pgtype.TextFormatCode, (*pgtype.Hstore)(nil)), 276 }, 277 { 278 "binary", 279 pgtype.HstoreCodec{}.PlanEncode(nil, 0, pgtype.BinaryFormatCode, pgtype.Hstore(nil)), 280 pgtype.HstoreCodec{}.PlanScan(nil, 0, pgtype.BinaryFormatCode, (*pgtype.Hstore)(nil)), 281 }, 282 } 283 284 inputs := []pgtype.Hstore{ 285 nil, 286 {}, 287 {"": stringPtr("")}, 288 {"k1": stringPtr("v1")}, 289 {"k1": stringPtr("v1"), "k2": stringPtr("v2")}, 290 } 291 for _, codec := range codecs { 292 for i, input := range inputs { 293 t.Run(fmt.Sprintf("%s/%d", codec.name, i), func(t *testing.T) { 294 serialized, err := codec.encodePlan.Encode(input, nil) 295 if err != nil { 296 t.Fatal(err) 297 } 298 var output pgtype.Hstore 299 err = codec.scanPlan.Scan(serialized, &output) 300 if err != nil { 301 t.Fatal(err) 302 } 303 if !reflect.DeepEqual(output, input) { 304 t.Errorf("output=%#v does not match input=%#v", output, input) 305 } 306 }) 307 } 308 } 309 310 } 311 312 func BenchmarkHstoreEncode(b *testing.B) { 313 h := pgtype.Hstore{"a x": stringPtr("100"), "b": stringPtr("200"), "c": stringPtr("300"), 314 "d": stringPtr("400"), "e": stringPtr("500")} 315 316 serializeConfigs := []struct { 317 name string 318 encodePlan pgtype.EncodePlan 319 }{ 320 {"text", pgtype.HstoreCodec{}.PlanEncode(nil, 0, pgtype.TextFormatCode, h)}, 321 {"binary", pgtype.HstoreCodec{}.PlanEncode(nil, 0, pgtype.BinaryFormatCode, h)}, 322 } 323 324 for _, serializeConfig := range serializeConfigs { 325 var buf []byte 326 b.Run(serializeConfig.name, func(b *testing.B) { 327 for i := 0; i < b.N; i++ { 328 var err error 329 buf, err = serializeConfig.encodePlan.Encode(h, buf) 330 if err != nil { 331 b.Fatal(err) 332 } 333 buf = buf[:0] 334 } 335 }) 336 } 337 } 338 339 func BenchmarkHstoreScan(b *testing.B) { 340 // empty, NULL, escapes, and based on some real data 341 benchStrings := []string{ 342 "", 343 `"a"=>"b"`, 344 `"a"=>"100", "b"=>"200", "c"=>"300", "d"=>"400", "e"=>"500"`, 345 `"a"=>"100", "b"=>NULL, "c"=>"300", "d"=>NULL, "e"=>"500"`, 346 `"pmd"=>"piokifjzxdy:mhvvmotns:sf1-dttudcp-orx-fuwzw-j8o-tl-jcg-1fb5d6dp50ke3l24", "ausz"=>"aorc-iosdby_tbxsjihj-kss64-32r128y-i2", "mgjo"=>"hxcp-ciag", "hkbee"=>"bokihheb", "gpcvhc"=>"ne-ywik-1", "olzjegk"=>"rxbkzba", "iy_quthhf"=>"sryizraxx", "bwpdpplfz"=>"gbdh-jikmnp_jwugdvjs-drh64-32k128h-p2", "njy_veipyyl"=>"727006795293", "vsgvqlrnqadzvk"=>"1_7_43", "mfdncuqvxp_gqlkytj"=>"fuyin", "cnuiswkwavoupqebov"=>"x32n128w", "mol_lcabioescln_ulstxauvi"=>"qm1-adbcand-tzi-fpnbv-s8j-vi-gqs-1om5b6lx50zk3u24", "arlyhgdxux.fc/bezucmz/mmfed"=>"vihsk", "jtkf.czddftrhr.ici/qbq_ftaz"=>"sse64", "notxkfqmpq.whxmykhtc.bcu/zmxz"=>"zauaklqp-uwo64-32q128a-g2", "ww_affdwqa_o8o_ilskcucq_urzltnf"=>"i6-9-0", "f8d.eq/bbqxwru-vsznvxerae/wsszbjw"=>"dgd", "ygpghkljze.dkrlrrieo.iur/xfqdqreft"=>"pfby-bhqlmm", "pmho-dqxuezyuu.ppslmznja.eam/ikehtxg"=>"wbku", "ckqeavtcqk.jiqdipgji.hjl/luzgqb-agm-wb"=>"ikpq", "akcn-yobdpxkyl.gktsjdo-xqwmivixku.p8y.vq/axqdw"=>"", "r8u.at/fbqrrss-ihxjmygoyc/ztqe-pqqqewnz/nepdj/njjv"=>"txtlffpp:ebwdksxkej", "q8x.wu/wenlhkz-govetdoibn/rcwg-ticalfjq/mgipy/awmjl"=>"dyzvbzvi", "p8l.wx/vadrnki-yfqhzlwcnt/hvun-geqhjsik/eqediipfr/vlc"=>"31900z", "t8z.be/qbtsmci-jqnqphssdg/ejma-slvywzry/txpnybwvn/kxdl"=>"210", "o8b.nb/bijgpwm-axvvqgujax/fjli-mxqwulfe/revyfoyty/oojpsd"=>"123421925786", "p8q.sk/ccpgzee-ufjempgvty/afwh-qvwzjvog/hsyhr/bklplujbfydtfw"=>"1_7_43", "k8y.jp/hqoymrw-flwqwvbntf/dlli-uggxkdqv/mtutu/qotjmacjitwtvcnblr"=>"m32x128f", "r8z.hj/eczodcw-lxzmeeqqii/fjba-psyoidht/gfjjcdbqs/apkqxiznu-muzubvl"=>"106068512341", "u8v.nf/ocnahkw-prhuwrrbjg/gxms-isohcouc/txfle/zfzw.neyygeeur.ejv/rnd_vdyo"=>"ibx64", "i8c.zz/dtiulqn-mmbskzjcib/fxuj-ejxbrnqi/optyp/wbbrancspv.pnkizgxcj.dbm/bldn"=>"znppnwzg-oxp64-32r128h-d2", "d8t.dg/jqtodoh-sokunyljow/svdf-ghplxxcx/wqkwl/dolljeqv.jcn.dxp.jmh.uyf/lyfv"=>"kc-lmpu-1i", "t8i.dy/imltbpr-atmthzarmk/fbbw-uaovyvdj/mmuwq/kseu-snmt.xtlgkstzph.mg/ehjdpgc"=>"", "o8c.yc/wximcpf-wmffadvnxx/tdim-szbqedqp/ztrui/puhx-kcwp.zziulqvvmb.ik/khfaxajj"=>"", "j8i.zc/sajavzi-kemnitliml/nloy-riqothpw/yxmnp/ttrnynffzy.lswpezbdq.wor/xkvqeexio"=>"ltmp-zajsxt", "a8f.xd/tfrrawy-ymihugugaa/ouzi-xdyecmqx/cwvgjvcrh/trgbxgbumo.uh/xmnqbds-nqxxeuqpq"=>"3123748065", "x8n.vx/juiqxkj-swvwogmncw/hvad-pojmevog/ytxit/auvo-duchssbth.uickilmnz.lja/hbeiakj"=>"hwhd", "z8j.bn/iplhrhv-wjdcwdclos/qndu-qvotchss/spvfx/brqotjnytw.aaemsoxor.ign/uwebjm-vzl-kb"=>"zwdg", "t8j.vx/iekvskm-xhikarvbty/czlm-xtipxwok/eeeow/uvtpuzmlqg.jgtpgiujc.wrs/mcofa-qxjjwak"=>"sovxb", "t8g.ab/wuncjdz-vsozsekgxz/aaea-hmgdjylm/qimwsoecgud-grgoowb/zveahbidvwcaebhlzigytiermehxy"=>"0.95", "n8k.ei/ohovibm-obkaatwlyw/bcow-gndyzpyt/aehyf/dpgifsorjx.ehsqntrka.jrr/meakdzy-ckxgnfavwm"=>"nlgw", "u8e.yi/qavbjew-qnmtzbeyce/rmwa-hcqlvadn/bhpml/taoj-wjnh.qqvkjmccfn.ja/nudbtwme-buc64-32j128i-k2"=>""`, 347 `"mbgs"=>"eqjillclhkxz", "bxci"=>"etksm.rudiu", "jijqqm"=>"kj-ryxhwqtco-2", "yivvcxy"=>"fwbujcu", "ybk_ztlajai"=>"601427279990"`, 348 `"wte"=>"nrhw", "lqjm"=>"ifsbygchn", "wbmf"=>"amjsoykkwq\\ghvwbsmz-qeiv-iekd-ukcwbipzy"`, 349 `"otx"=>"fcreomqbwtk:gqhxzhxuh:wrqo-rf1-avhdpfy-nqi-dldof-i8p-mw-jll-l5r9741753c3", "vbjy"=>"akzfspigip_muzyxzwuso-zvoifh-uw", "fmkb"=>"pkoe-lezf", "wfbq"=>"qoviagajeg", "zvxbiv"=>"db-bcngmoq-1", "olictqnpx"=>"taqcnrcwcj_ticfxydekq-fafbkg-ot", "wkt_jtzzqpt"=>"727006795293", "bsdncvmbvj_xivgkws"=>"zczag", "muzq.oyrphhtne.fqm/itc"=>"ihilzgx", "pfsd.xphmjdohu.hrm/yeimpfm"=>"lrrqxrwyud-uvcljo", "qukdxappwo.or/xgcsmdo/dodoj"=>"onflq", "ktqrsqtllo.xxxpkizlg.tnf/unrt"=>"jrveutvddu-loihei-ww", "tr_qmarsis_s8v_skzbuuvy_cnyuxyk"=>"g6-16-0", "z8q.yc/xistcyy-tftbikuuhg/zvhemmi"=>"knv", "zrgwpjnvzq.twkcxxuyk.qwc/nirbacaom"=>"okfdlcpbdg", "suvk-wwwjqdytq.wdjmzxl-nduettmnmf.e8e.ec/qhkan"=>"", "u8m.xa/uvbhlmw-rqrcyyaiju/otsg-bqjfitoq/zqfuq/fifo"=>"brarmrogdb", "b8o.ci/znwkyby-nzuxiguqus/nwou-cxxnqxrr/rtdsp/yawv"=>"juedpptnbt-khocdt-vg:vfxpdswxnc", "u8h.vl/kgmvysr-xhykrjcssj/jfjv-gzalgika/yhrjfytwz/kbm"=>"3900f", "y8b.cm/ttijscl-rznjossaqw/kvto-gvnavnep/bwdqyuzgo/ozoi"=>"40", "p8j.pd/bnucngv-vnqufgvfqw/qshw-obnkmlfx/obczheyis/zzbsos"=>"7009zf", "p8y.fc/ejbndrq-aariupaovi/mrah-hmrhjcsv/lvrmfwwiz/uskogxfuw-zamygae"=>"18747532246", "y8m.oh/xzuhilr-wqmqqzcznb/pcox-idpxmhfj/yzsoj/qebkjaeymc.abqznnelq.gyd/osvb"=>"hsgxlccalq-eeybug-mx", "p8f.ay/tyntrss-nljxedfihd/grvy-znfykhlf/fjsqd/ffxaixyv.jie.bkg.zpd.kim/mgtc"=>"or-vrkdcxm-1i", "i8m.ms/jtykfbi-jdrqsqjdwt/ibaq-zmeuyznf/uczny/ufmj-zklt.omodkgubqw.ip/xztdevd"=>"", "k8m.ui/ymxurqo-kuhofnewjj/twex-iuwljutj/warlx/zptkdgqdpr.uhvqtrclx.ohj/bdkgsozkk"=>"zlgisdikac", "g8b.wk/vecudfr-pljllpgzxi/lbwd-zsracrgq/fucssaowj/syizbmlfqt.si/swpbend-gxrhddxad"=>"156213905", "z8y.ah/azeasta-gffxfwklrn/hukw-hphwntwy/lfswv/tmaeaxekya.vgkxjhtvg.mht/bzolt-koioxpf"=>"wzkra", "f8l.sy/ouekhco-rlhsclfzwx/erfz-uuejogrs/bgvia/zpohrhmrmu.sbdxzlaxo.wii/jbnwfvz-shekbewool"=>"aiey", "j8w.pz/fjtkxhn-zxxizfldde/wsik-uiodldga/ljdtl/gswz-cjmt.ffkelhxcsd.lw/ftcqgdnnho-ibbfql-ww"=>""`, 350 `"uvd"=>"oneotg", "wsm"=>"djjgmwqyple:jtxtfvtjv:du1-nfxzmra-idl-ikxbx-t8n-id-nbo-6d08opx70381", "orq"=>"bkdvjw-xydgbd1", "gblm"=>"jtkcfd-unxbag1_xagyfw-nvachf1", "mfer"=>"jclz-yaim", "jvgvas"=>"jf-vhxh-1", "wwardeuqu"=>"ufimeb-bscfdy1_bfuagy-dhdqra1", "szs_rfgpqmc"=>"727006795293", "ckfxcgrnqc_rloxzxu"=>"qffbw", "yaigdvscju.ba/krpgzji/wvxyg"=>"srgtu", "gtxfjsigdv.pxujnffnp.aza/ycco"=>"ntranp-ahgeem1", "xj_lhdpvsl_i8i_qzrtlpjr_nroujqh"=>"q6-1-8", "czxy-sfym.enlohvvjmp.wb/huvcuhy"=>"", "x8a.of/sqpdqiq-vijrlgkkyl/oncckls"=>"mij", "oomgvfopmc.trnzktrtz.gza/rpeqqyqmm"=>"rgwnma-bwcbxe1", "gaud-giar.xuablvwkbo.wy/wvhmsk-uaycqn1"=>"", "oarbmcqzzw.qkfbtmltz.plh/aqssj-tlrhsof"=>"wxfd", "zepirccplb.qanvqnxlo.eld/emulnov-vgddsefeqv"=>"jnvh", "acby-kywxjuczc.suosfcy-drsgroeqvy.o8m.og/vyuxt"=>"", "q8j.by/lrwxbjt-yzrenlniog/gbmw-mnokcndu/etbcy/ibwr"=>"qpttug-jnxhwe1:grmslxhyky", "i8y.uy/awavkxk-nztmqujxys/pocu-sqjdqvzd/tfdjeflpn/xsj"=>"7900c", "z8g.ia/yzfdvta-ffkciorpfl/kmjc-fgcdomlv/snvhhbjil/nhvn"=>"45", "s8l.ky/dtvxoqu-lzfdnykmdh/wtdg-aktximmy/hofzkpzel/wtghso"=>"14837zg", "v8e.rq/uosznaz-drypoapgpe/vxss-mbxmvkjj/oglvxhxcz/whutvtjmr-tewtidr"=>"18747532246", "m8p.sz/hrgniti-aufhjdsdcc/whcp-cfuwjsnl/exugj/evphviokhl.ashpndixr.jvx/vgtt"=>"zdsacy-ppfuxf1", "w8t.fm/kljwjgc-fijbwsrvxa/dbzl-fhxvlrwk/yidyk/orrt-kgpr.wuzmpnxvtb.lc/dmbqfvt"=>"", "m8j.sv/takylmm-ywnolaflnl/ueih-fdcpfcpv/dslbc/dsspusnhtu.vgkihqtpb.fto/qmyksglfx"=>"wpwuih-deuiej1", "m8x.wi/jwobkio-mwupghbqbi/krqn-hqyfgwuw/mcbyi/yzkt-wtdy.pjxevrogab.tj/qlttbz-ppyzkd1"=>"", "c8j.tr/tzcbhid-lggaiypnny/wyms-zcjgxmwp/eaohd/bcwkheknsr.fqvtgecsf.qbf/uaqzj-jburpix"=>"ckkk", "w8h.wk/msbqvqy-nsmvbojwns/edpo-nsivbrmx/qifaf/sopuabsuvq.foyniwomd.zvj/lhvfwvv-zuufhhspso"=>"fghx"`, 351 `"xxtlvd"=>"ba-zrzy-1", "hlebkcl"=>"entrcad", "ytn_toivqso"=>"601427279990", "czdllqyvkcfemhubpwvxakepubup"=>"jzhpff-vn2-sgiupfiii-qmuuz-ndex-vin-kmfm", "mefjcnjmcspgviisjalxmwdbksmge"=>"2022-11-20"`, 352 `"ukq"=>"uhkbdj", "bmj"=>"mcoknsnhqcb:vmexvsccu:yt1-nscwdfr-zcp-ajfhr-z8i-ta-jhv-58yl03459t86", "cuq"=>"sqphbh-xkxbcgwdx", "dnac"=>"khzjpq-hljdvlbsw_azdisd-nshizhinc", "flgj"=>"zeem-pggu", "ksnn"=>"vpittgnl-xeojllby-toq", "wwxepg"=>"ki-cwee-1", "vigdnntxw"=>"sydsls-zidlsgugi_wviqvl-umwzyztab", "osz_utmlghi"=>"727006795293", "wacdaefqhc_buqmsci"=>"djtcv", "ljdbotgrsi.xn/gvtjfeg/iiyek"=>"lnfgg", "sohcclfodf.wkwiitult.ppm/hhsf"=>"ecpftm-ecmsibfjy", "dz_cgfnddq_o8j_cowdxlfz_rmjunpm"=>"v5-13-1", "niwk-fozq.tbamcxrhez.kl/zuxnisw"=>"", "h8k.xu/nbsezqz-fopcyqlnwt/lfcmgag"=>"dmm", "zebgpskksd.daigyeicb.dlj/dwmcpkohh"=>"hegecl-bnqmkunkl", "irjreiuove.qpmjixctw.mzv/xizjv-bpecdmy"=>"rkfl", "fupz-eiim.hwaqzvpzgv.yg/zhrqmr-qcydocyak"=>"", "djuscbflju.fmhnephvc.cmo/wzcisia-kqmrrhnkiv"=>"vchu", "hauo-olkeyvbrz.qzpaocu-wdbyfrzjkx.c8a.rn/bwhfe"=>"", "l8d.fj/jzojrmv-mbnxftbdzg/qvgo-oayrldze/tqmoa/oizo"=>"buwgyd-bjlrzrlci:ywosrfsnts", "q8l.sj/vifqvao-ynvfejvleb/ourc-jzridgtt/fgxnueuvm/wsg"=>"7900p", "d8b.mi/steijrv-bgajdbugff/kxkj-jhvctoxw/seyrafhni/xxrc"=>"45", "x8k.bn/dnnkttb-ywqrwwxirk/ngvt-eqyaeqsd/qesxmjfos/nlolbe"=>"14837xp", "v8o.az/vtbyyyo-rjuadsmwyb/gszv-ytnisfau/kfunvihsr/famkeacyo-skpueao"=>"18747532246", "f8w.ip/sjzrxbw-idgsgucprq/ster-zxiilwcf/luwzw/tavccuqfph.mcubdrtcr.ibw/dxnj"=>"ntyjnf-zwlyjqbfq", "y8f.mh/qykpkfr-fsnlckrhpe/hvyu-vstwrxkq/dmesn/kuor-acub.fqwqxcpiet.jf/zaxtdyb"=>"", "c8m.et/ekavnnp-gvpmldvoou/jzva-zzzpiecc/dvckb/qqxrfpoaiy.ssfqerwmb.cnz/odsfndorh"=>"liilkb-aekfuqzss", "e8n.gp/sybrxvz-mghjbpphpc/wcuo-naanbtcj/agtov/dztlgdacuz.fpbhhiybg.ncm/otgfu-hnezrwu"=>"ccez", "t8h.cy/bqsdiil-lxmioonwjt/drsw-qevzljvt/rvzjl/btbz-npvi.ypyxowgmfp.gf/jcfbyh-khpgbaayw"=>"", "y8b.df/anmudfn-gahfengbqw/fhdi-ozqtddmu/lvviu/kndwvowlby.jxkizwkac.hbq/fjkqyna-jijxahivma"=>"wxqg"`, 353 } 354 355 // convert benchStrings into text and binary bytes 356 textBytes := make([][]byte, len(benchStrings)) 357 binaryBytes := make([][]byte, len(benchStrings)) 358 codec := pgtype.HstoreCodec{}.PlanEncode(nil, 0, pgtype.BinaryFormatCode, pgtype.Hstore(nil)) 359 for i, s := range benchStrings { 360 textBytes[i] = []byte(s) 361 362 var tempH pgtype.Hstore 363 err := tempH.Scan(s) 364 if err != nil { 365 b.Fatal(err) 366 } 367 binaryBytes[i], err = codec.Encode(tempH, nil) 368 if err != nil { 369 b.Fatal(err) 370 } 371 } 372 373 // benchmark the database/sql.Scan API 374 var h pgtype.Hstore 375 b.Run("databasesql.Scan", func(b *testing.B) { 376 b.ReportAllocs() 377 for i := 0; i < b.N; i++ { 378 for _, str := range benchStrings { 379 err := h.Scan(str) 380 if err != nil { 381 b.Fatal(err) 382 } 383 } 384 } 385 }) 386 387 // benchmark the []byte scan API used by pgconn 388 scanConfigs := []struct { 389 name string 390 scanPlan pgtype.ScanPlan 391 inputBytes [][]byte 392 }{ 393 {"text", pgtype.HstoreCodec{}.PlanScan(nil, 0, pgtype.TextFormatCode, &h), textBytes}, 394 {"binary", pgtype.HstoreCodec{}.PlanScan(nil, 0, pgtype.BinaryFormatCode, &h), binaryBytes}, 395 } 396 for _, scanConfig := range scanConfigs { 397 b.Run(scanConfig.name, func(b *testing.B) { 398 b.ReportAllocs() 399 for i := 0; i < b.N; i++ { 400 for _, input := range scanConfig.inputBytes { 401 err := scanConfig.scanPlan.Scan(input, &h) 402 if err != nil { 403 b.Fatalf("input=%#v err=%s", string(input), err) 404 } 405 } 406 } 407 }) 408 } 409 }