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  }