{"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/compare/v2.1.13...v2.1.14","html_url":"https://github.com/aws/amazon-redshift-python-driver/compare/v2.1.13...v2.1.14","permalink_url":"https://github.com/aws/amazon-redshift-python-driver/compare/aws:f034099...aws:2b83976","diff_url":"https://github.com/aws/amazon-redshift-python-driver/compare/v2.1.13...v2.1.14.diff","patch_url":"https://github.com/aws/amazon-redshift-python-driver/compare/v2.1.13...v2.1.14.patch","base_commit":{"sha":"f034099eea1620e499641db071f81ec1866f698c","node_id":"C_kwDOEOee_NoAKGYwMzQwOTllZWExNjIwZTQ5OTY0MWRiMDcxZjgxZWMxODY2ZjY5OGM","commit":{"author":{"name":"stinghsu","email":"stinghsu@amazon.com","date":"2026-03-31T00:55:52Z"},"committer":{"name":"GitHub","email":"noreply@github.com","date":"2026-03-31T00:55:52Z"},"message":"Update CHANGELOG.md","tree":{"sha":"5a6fe550811dcd9ffab02940545c20ff294c4b3f","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/trees/5a6fe550811dcd9ffab02940545c20ff294c4b3f"},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/commits/f034099eea1620e499641db071f81ec1866f698c","comment_count":0,"verification":{"verified":true,"reason":"valid","signature":"-----BEGIN PGP SIGNATURE-----\n\nwsFcBAABCAAQBQJpyxuYCRC1aQ7uu5UhlAAAUDoQAH2wXtC8cNZEXYI3pDRaRdTT\nd4MbHw7rOk028Zsci4/9Y2k7VoVtawoQ/fnDQSXSMUfchO6VhwzeOiBpd6gNDnOe\necm1BTiaztLz3zH7loQsL5LJwZIQ4OG8eZNH1ZfRmuH2ylYiECcPKSHTJFFf+KJ+\noJokBUMyyu7fzoSgrWOltU1PwMESQMnaAZwKulC5nW4LdTkqCv8AG8hN2JFJKDN9\np2XboLLZzXox9FdoWB1PBLbolRxeW2QKk+Z9488jqkOvmasBd8X+QVkKkt/ZwVDL\nFcGhGP15qg/vHB2w+iFCzBu2TGkoXLMgu05qPwbT50lhhApWkQK3gup/iXJnnz6B\nmOWiWQXh8PtUMqCeo+S1f0lTeyQNdFp+mjmQJDTecvvijKv9bjxYxtPbFsUxf0EX\n9E644QPHwT67wX6dlMolpAa0jwVA1OLH4tXGyiwkEe5x75bEG8s/DSVs831rMur0\nBUBScVk/N5vMTa7xsB+S5lWGcJmn4KiAbTdju+I9trHBEy504MyLphcB7dH3tNwx\nFSzZfbZZuG0buCyz5rnV/C7Bs/2K8GP2gTNINUe/nRRoszvnm59mSy6YpdpPScvV\nXn2UzooWVbEPkBUnYxvY2F9Mqb3fvBfbUNxJ2s5gNurqJtXmY6EabWpoU6Ry7q0O\n3XckIJmqZYVYiCDeeo2e\n=2Kif\n-----END PGP SIGNATURE-----\n","payload":"tree 5a6fe550811dcd9ffab02940545c20ff294c4b3f\nparent 537001fabee42c1f57c5b0de8c543dea8325f6df\nauthor stinghsu <stinghsu@amazon.com> 1774918552 -0700\ncommitter GitHub <noreply@github.com> 1774918552 -0700\n\nUpdate CHANGELOG.md","verified_at":"2026-03-31T00:55:52Z"}},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/f034099eea1620e499641db071f81ec1866f698c","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/f034099eea1620e499641db071f81ec1866f698c","comments_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/f034099eea1620e499641db071f81ec1866f698c/comments","author":{"login":"timm4205","id":169836602,"node_id":"U_kgDOCh-AOg","avatar_url":"https://avatars.githubusercontent.com/u/169836602?v=4","gravatar_id":"","url":"https://api.github.com/users/timm4205","html_url":"https://github.com/timm4205","followers_url":"https://api.github.com/users/timm4205/followers","following_url":"https://api.github.com/users/timm4205/following{/other_user}","gists_url":"https://api.github.com/users/timm4205/gists{/gist_id}","starred_url":"https://api.github.com/users/timm4205/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/timm4205/subscriptions","organizations_url":"https://api.github.com/users/timm4205/orgs","repos_url":"https://api.github.com/users/timm4205/repos","events_url":"https://api.github.com/users/timm4205/events{/privacy}","received_events_url":"https://api.github.com/users/timm4205/received_events","type":"User","user_view_type":"public","site_admin":false},"committer":{"login":"web-flow","id":19864447,"node_id":"MDQ6VXNlcjE5ODY0NDQ3","avatar_url":"https://avatars.githubusercontent.com/u/19864447?v=4","gravatar_id":"","url":"https://api.github.com/users/web-flow","html_url":"https://github.com/web-flow","followers_url":"https://api.github.com/users/web-flow/followers","following_url":"https://api.github.com/users/web-flow/following{/other_user}","gists_url":"https://api.github.com/users/web-flow/gists{/gist_id}","starred_url":"https://api.github.com/users/web-flow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/web-flow/subscriptions","organizations_url":"https://api.github.com/users/web-flow/orgs","repos_url":"https://api.github.com/users/web-flow/repos","events_url":"https://api.github.com/users/web-flow/events{/privacy}","received_events_url":"https://api.github.com/users/web-flow/received_events","type":"User","user_view_type":"public","site_admin":false},"parents":[{"sha":"537001fabee42c1f57c5b0de8c543dea8325f6df","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/537001fabee42c1f57c5b0de8c543dea8325f6df","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/537001fabee42c1f57c5b0de8c543dea8325f6df"}]},"merge_base_commit":{"sha":"f034099eea1620e499641db071f81ec1866f698c","node_id":"C_kwDOEOee_NoAKGYwMzQwOTllZWExNjIwZTQ5OTY0MWRiMDcxZjgxZWMxODY2ZjY5OGM","commit":{"author":{"name":"stinghsu","email":"stinghsu@amazon.com","date":"2026-03-31T00:55:52Z"},"committer":{"name":"GitHub","email":"noreply@github.com","date":"2026-03-31T00:55:52Z"},"message":"Update CHANGELOG.md","tree":{"sha":"5a6fe550811dcd9ffab02940545c20ff294c4b3f","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/trees/5a6fe550811dcd9ffab02940545c20ff294c4b3f"},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/commits/f034099eea1620e499641db071f81ec1866f698c","comment_count":0,"verification":{"verified":true,"reason":"valid","signature":"-----BEGIN PGP SIGNATURE-----\n\nwsFcBAABCAAQBQJpyxuYCRC1aQ7uu5UhlAAAUDoQAH2wXtC8cNZEXYI3pDRaRdTT\nd4MbHw7rOk028Zsci4/9Y2k7VoVtawoQ/fnDQSXSMUfchO6VhwzeOiBpd6gNDnOe\necm1BTiaztLz3zH7loQsL5LJwZIQ4OG8eZNH1ZfRmuH2ylYiECcPKSHTJFFf+KJ+\noJokBUMyyu7fzoSgrWOltU1PwMESQMnaAZwKulC5nW4LdTkqCv8AG8hN2JFJKDN9\np2XboLLZzXox9FdoWB1PBLbolRxeW2QKk+Z9488jqkOvmasBd8X+QVkKkt/ZwVDL\nFcGhGP15qg/vHB2w+iFCzBu2TGkoXLMgu05qPwbT50lhhApWkQK3gup/iXJnnz6B\nmOWiWQXh8PtUMqCeo+S1f0lTeyQNdFp+mjmQJDTecvvijKv9bjxYxtPbFsUxf0EX\n9E644QPHwT67wX6dlMolpAa0jwVA1OLH4tXGyiwkEe5x75bEG8s/DSVs831rMur0\nBUBScVk/N5vMTa7xsB+S5lWGcJmn4KiAbTdju+I9trHBEy504MyLphcB7dH3tNwx\nFSzZfbZZuG0buCyz5rnV/C7Bs/2K8GP2gTNINUe/nRRoszvnm59mSy6YpdpPScvV\nXn2UzooWVbEPkBUnYxvY2F9Mqb3fvBfbUNxJ2s5gNurqJtXmY6EabWpoU6Ry7q0O\n3XckIJmqZYVYiCDeeo2e\n=2Kif\n-----END PGP SIGNATURE-----\n","payload":"tree 5a6fe550811dcd9ffab02940545c20ff294c4b3f\nparent 537001fabee42c1f57c5b0de8c543dea8325f6df\nauthor stinghsu <stinghsu@amazon.com> 1774918552 -0700\ncommitter GitHub <noreply@github.com> 1774918552 -0700\n\nUpdate CHANGELOG.md","verified_at":"2026-03-31T00:55:52Z"}},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/f034099eea1620e499641db071f81ec1866f698c","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/f034099eea1620e499641db071f81ec1866f698c","comments_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/f034099eea1620e499641db071f81ec1866f698c/comments","author":{"login":"timm4205","id":169836602,"node_id":"U_kgDOCh-AOg","avatar_url":"https://avatars.githubusercontent.com/u/169836602?v=4","gravatar_id":"","url":"https://api.github.com/users/timm4205","html_url":"https://github.com/timm4205","followers_url":"https://api.github.com/users/timm4205/followers","following_url":"https://api.github.com/users/timm4205/following{/other_user}","gists_url":"https://api.github.com/users/timm4205/gists{/gist_id}","starred_url":"https://api.github.com/users/timm4205/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/timm4205/subscriptions","organizations_url":"https://api.github.com/users/timm4205/orgs","repos_url":"https://api.github.com/users/timm4205/repos","events_url":"https://api.github.com/users/timm4205/events{/privacy}","received_events_url":"https://api.github.com/users/timm4205/received_events","type":"User","user_view_type":"public","site_admin":false},"committer":{"login":"web-flow","id":19864447,"node_id":"MDQ6VXNlcjE5ODY0NDQ3","avatar_url":"https://avatars.githubusercontent.com/u/19864447?v=4","gravatar_id":"","url":"https://api.github.com/users/web-flow","html_url":"https://github.com/web-flow","followers_url":"https://api.github.com/users/web-flow/followers","following_url":"https://api.github.com/users/web-flow/following{/other_user}","gists_url":"https://api.github.com/users/web-flow/gists{/gist_id}","starred_url":"https://api.github.com/users/web-flow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/web-flow/subscriptions","organizations_url":"https://api.github.com/users/web-flow/orgs","repos_url":"https://api.github.com/users/web-flow/repos","events_url":"https://api.github.com/users/web-flow/events{/privacy}","received_events_url":"https://api.github.com/users/web-flow/received_events","type":"User","user_view_type":"public","site_admin":false},"parents":[{"sha":"537001fabee42c1f57c5b0de8c543dea8325f6df","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/537001fabee42c1f57c5b0de8c543dea8325f6df","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/537001fabee42c1f57c5b0de8c543dea8325f6df"}]},"status":"ahead","ahead_by":6,"behind_by":0,"total_commits":6,"commits":[{"sha":"e4c0d721b1dbe9f7f6c3b764019518483a34b26e","node_id":"C_kwDOEOee_NoAKGU0YzBkNzIxYjFkYmU5ZjdmNmMzYjc2NDAxOTUxODQ4M2EzNGIyNmU","commit":{"author":{"name":"Tim Hsu","email":"stinghsu@amazon.com","date":"2026-05-18T19:28:44Z"},"committer":{"name":"Ruei-Yang Huang","email":"ryhuang@amazon.com","date":"2026-05-18T19:28:44Z"},"message":"Added test for IDP token auth integration","tree":{"sha":"ba46450d4e26c56f4474ac55c0d859d7e9fec209","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/trees/ba46450d4e26c56f4474ac55c0d859d7e9fec209"},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/commits/e4c0d721b1dbe9f7f6c3b764019518483a34b26e","comment_count":0,"verification":{"verified":false,"reason":"unsigned","signature":null,"payload":null,"verified_at":null}},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/e4c0d721b1dbe9f7f6c3b764019518483a34b26e","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/e4c0d721b1dbe9f7f6c3b764019518483a34b26e","comments_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/e4c0d721b1dbe9f7f6c3b764019518483a34b26e/comments","author":{"login":"timm4205","id":169836602,"node_id":"U_kgDOCh-AOg","avatar_url":"https://avatars.githubusercontent.com/u/169836602?v=4","gravatar_id":"","url":"https://api.github.com/users/timm4205","html_url":"https://github.com/timm4205","followers_url":"https://api.github.com/users/timm4205/followers","following_url":"https://api.github.com/users/timm4205/following{/other_user}","gists_url":"https://api.github.com/users/timm4205/gists{/gist_id}","starred_url":"https://api.github.com/users/timm4205/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/timm4205/subscriptions","organizations_url":"https://api.github.com/users/timm4205/orgs","repos_url":"https://api.github.com/users/timm4205/repos","events_url":"https://api.github.com/users/timm4205/events{/privacy}","received_events_url":"https://api.github.com/users/timm4205/received_events","type":"User","user_view_type":"public","site_admin":false},"committer":{"login":"rueiyhuang","id":134524501,"node_id":"U_kgDOCASuVQ","avatar_url":"https://avatars.githubusercontent.com/u/134524501?v=4","gravatar_id":"","url":"https://api.github.com/users/rueiyhuang","html_url":"https://github.com/rueiyhuang","followers_url":"https://api.github.com/users/rueiyhuang/followers","following_url":"https://api.github.com/users/rueiyhuang/following{/other_user}","gists_url":"https://api.github.com/users/rueiyhuang/gists{/gist_id}","starred_url":"https://api.github.com/users/rueiyhuang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rueiyhuang/subscriptions","organizations_url":"https://api.github.com/users/rueiyhuang/orgs","repos_url":"https://api.github.com/users/rueiyhuang/repos","events_url":"https://api.github.com/users/rueiyhuang/events{/privacy}","received_events_url":"https://api.github.com/users/rueiyhuang/received_events","type":"User","user_view_type":"public","site_admin":false},"parents":[{"sha":"f034099eea1620e499641db071f81ec1866f698c","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/f034099eea1620e499641db071f81ec1866f698c","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/f034099eea1620e499641db071f81ec1866f698c"}]},{"sha":"2c1dd5b9aca1945a1b8e01b2359075d9e8b0e77c","node_id":"C_kwDOEOee_NoAKDJjMWRkNWI5YWNhMTk0NWExYjhlMDFiMjM1OTA3NWQ5ZThiMGU3N2M","commit":{"author":{"name":"Tim Hsu","email":"stinghsu@amazon.com","date":"2026-05-18T19:29:46Z"},"committer":{"name":"Ruei-Yang Huang","email":"ryhuang@amazon.com","date":"2026-05-18T19:29:46Z"},"message":"Added support for pg_catalog internal data types in the getFunctionColumns and getProcedureColumns metadata APIs.","tree":{"sha":"b5a33a85f40a8abde075b1db76114c8f93ff2e56","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/trees/b5a33a85f40a8abde075b1db76114c8f93ff2e56"},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/commits/2c1dd5b9aca1945a1b8e01b2359075d9e8b0e77c","comment_count":0,"verification":{"verified":false,"reason":"unsigned","signature":null,"payload":null,"verified_at":null}},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/2c1dd5b9aca1945a1b8e01b2359075d9e8b0e77c","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/2c1dd5b9aca1945a1b8e01b2359075d9e8b0e77c","comments_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/2c1dd5b9aca1945a1b8e01b2359075d9e8b0e77c/comments","author":{"login":"timm4205","id":169836602,"node_id":"U_kgDOCh-AOg","avatar_url":"https://avatars.githubusercontent.com/u/169836602?v=4","gravatar_id":"","url":"https://api.github.com/users/timm4205","html_url":"https://github.com/timm4205","followers_url":"https://api.github.com/users/timm4205/followers","following_url":"https://api.github.com/users/timm4205/following{/other_user}","gists_url":"https://api.github.com/users/timm4205/gists{/gist_id}","starred_url":"https://api.github.com/users/timm4205/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/timm4205/subscriptions","organizations_url":"https://api.github.com/users/timm4205/orgs","repos_url":"https://api.github.com/users/timm4205/repos","events_url":"https://api.github.com/users/timm4205/events{/privacy}","received_events_url":"https://api.github.com/users/timm4205/received_events","type":"User","user_view_type":"public","site_admin":false},"committer":{"login":"rueiyhuang","id":134524501,"node_id":"U_kgDOCASuVQ","avatar_url":"https://avatars.githubusercontent.com/u/134524501?v=4","gravatar_id":"","url":"https://api.github.com/users/rueiyhuang","html_url":"https://github.com/rueiyhuang","followers_url":"https://api.github.com/users/rueiyhuang/followers","following_url":"https://api.github.com/users/rueiyhuang/following{/other_user}","gists_url":"https://api.github.com/users/rueiyhuang/gists{/gist_id}","starred_url":"https://api.github.com/users/rueiyhuang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rueiyhuang/subscriptions","organizations_url":"https://api.github.com/users/rueiyhuang/orgs","repos_url":"https://api.github.com/users/rueiyhuang/repos","events_url":"https://api.github.com/users/rueiyhuang/events{/privacy}","received_events_url":"https://api.github.com/users/rueiyhuang/received_events","type":"User","user_view_type":"public","site_admin":false},"parents":[{"sha":"e4c0d721b1dbe9f7f6c3b764019518483a34b26e","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/e4c0d721b1dbe9f7f6c3b764019518483a34b26e","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/e4c0d721b1dbe9f7f6c3b764019518483a34b26e"}]},{"sha":"69a69dfdead75918e20384da52bcd760ded8dbca","node_id":"C_kwDOEOee_NoAKDY5YTY5ZGZkZWFkNzU5MThlMjAzODRkYTUyYmNkNzYwZGVkOGRiY2E","commit":{"author":{"name":"Subham Kumar","email":"psubhku@amazon.com","date":"2026-05-18T19:31:37Z"},"committer":{"name":"Ruei-Yang Huang","email":"ryhuang@amazon.com","date":"2026-05-18T19:31:37Z"},"message":"Replaced eval() usage in vector_in() type handler with integer parsing","tree":{"sha":"ce4d65531c2044e4be421da34585ee42c90d5cf3","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/trees/ce4d65531c2044e4be421da34585ee42c90d5cf3"},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/commits/69a69dfdead75918e20384da52bcd760ded8dbca","comment_count":0,"verification":{"verified":false,"reason":"unsigned","signature":null,"payload":null,"verified_at":null}},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/69a69dfdead75918e20384da52bcd760ded8dbca","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/69a69dfdead75918e20384da52bcd760ded8dbca","comments_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/69a69dfdead75918e20384da52bcd760ded8dbca/comments","author":null,"committer":{"login":"rueiyhuang","id":134524501,"node_id":"U_kgDOCASuVQ","avatar_url":"https://avatars.githubusercontent.com/u/134524501?v=4","gravatar_id":"","url":"https://api.github.com/users/rueiyhuang","html_url":"https://github.com/rueiyhuang","followers_url":"https://api.github.com/users/rueiyhuang/followers","following_url":"https://api.github.com/users/rueiyhuang/following{/other_user}","gists_url":"https://api.github.com/users/rueiyhuang/gists{/gist_id}","starred_url":"https://api.github.com/users/rueiyhuang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rueiyhuang/subscriptions","organizations_url":"https://api.github.com/users/rueiyhuang/orgs","repos_url":"https://api.github.com/users/rueiyhuang/repos","events_url":"https://api.github.com/users/rueiyhuang/events{/privacy}","received_events_url":"https://api.github.com/users/rueiyhuang/received_events","type":"User","user_view_type":"public","site_admin":false},"parents":[{"sha":"2c1dd5b9aca1945a1b8e01b2359075d9e8b0e77c","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/2c1dd5b9aca1945a1b8e01b2359075d9e8b0e77c","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/2c1dd5b9aca1945a1b8e01b2359075d9e8b0e77c"}]},{"sha":"b08497046600dd2f950f29f7cc3d1d67265e38ce","node_id":"C_kwDOEOee_NoAKGIwODQ5NzA0NjYwMGRkMmY5NTBmMjlmN2NjM2QxZDY3MjY1ZTM4Y2U","commit":{"author":{"name":"Nithin Subramoniam","email":"nithisub@amazon.com","date":"2026-05-18T19:33:31Z"},"committer":{"name":"Ruei-Yang Huang","email":"ryhuang@amazon.com","date":"2026-05-18T19:35:15Z"},"message":"Addressed security issue as detailed in CVE-2026-41066","tree":{"sha":"67b0a3c8b6d90f6a22af46daef4a17ee3b4a51d2","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/trees/67b0a3c8b6d90f6a22af46daef4a17ee3b4a51d2"},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/commits/b08497046600dd2f950f29f7cc3d1d67265e38ce","comment_count":0,"verification":{"verified":false,"reason":"unsigned","signature":null,"payload":null,"verified_at":null}},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/b08497046600dd2f950f29f7cc3d1d67265e38ce","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/b08497046600dd2f950f29f7cc3d1d67265e38ce","comments_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/b08497046600dd2f950f29f7cc3d1d67265e38ce/comments","author":{"login":"nithisub","id":221394580,"node_id":"U_kgDODTI2lA","avatar_url":"https://avatars.githubusercontent.com/u/221394580?v=4","gravatar_id":"","url":"https://api.github.com/users/nithisub","html_url":"https://github.com/nithisub","followers_url":"https://api.github.com/users/nithisub/followers","following_url":"https://api.github.com/users/nithisub/following{/other_user}","gists_url":"https://api.github.com/users/nithisub/gists{/gist_id}","starred_url":"https://api.github.com/users/nithisub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nithisub/subscriptions","organizations_url":"https://api.github.com/users/nithisub/orgs","repos_url":"https://api.github.com/users/nithisub/repos","events_url":"https://api.github.com/users/nithisub/events{/privacy}","received_events_url":"https://api.github.com/users/nithisub/received_events","type":"User","user_view_type":"public","site_admin":false},"committer":{"login":"rueiyhuang","id":134524501,"node_id":"U_kgDOCASuVQ","avatar_url":"https://avatars.githubusercontent.com/u/134524501?v=4","gravatar_id":"","url":"https://api.github.com/users/rueiyhuang","html_url":"https://github.com/rueiyhuang","followers_url":"https://api.github.com/users/rueiyhuang/followers","following_url":"https://api.github.com/users/rueiyhuang/following{/other_user}","gists_url":"https://api.github.com/users/rueiyhuang/gists{/gist_id}","starred_url":"https://api.github.com/users/rueiyhuang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rueiyhuang/subscriptions","organizations_url":"https://api.github.com/users/rueiyhuang/orgs","repos_url":"https://api.github.com/users/rueiyhuang/repos","events_url":"https://api.github.com/users/rueiyhuang/events{/privacy}","received_events_url":"https://api.github.com/users/rueiyhuang/received_events","type":"User","user_view_type":"public","site_admin":false},"parents":[{"sha":"69a69dfdead75918e20384da52bcd760ded8dbca","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/69a69dfdead75918e20384da52bcd760ded8dbca","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/69a69dfdead75918e20384da52bcd760ded8dbca"}]},{"sha":"fbb64e54134ccd8306d022e4bf48bcf52b648675","node_id":"C_kwDOEOee_NoAKGZiYjY0ZTU0MTM0Y2NkODMwNmQwMjJlNGJmNDhiY2Y1MmI2NDg2NzU","commit":{"author":{"name":"Ruei-Yang Huang","email":"ryhuang@amazon.com","date":"2026-05-18T19:35:54Z"},"committer":{"name":"Ruei-Yang Huang","email":"ryhuang@amazon.com","date":"2026-05-18T19:35:54Z"},"message":"Version bump to 2.1.14","tree":{"sha":"570969adceaed3d79b3bfcb05486eb0464db95ed","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/trees/570969adceaed3d79b3bfcb05486eb0464db95ed"},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/commits/fbb64e54134ccd8306d022e4bf48bcf52b648675","comment_count":0,"verification":{"verified":false,"reason":"unsigned","signature":null,"payload":null,"verified_at":null}},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/fbb64e54134ccd8306d022e4bf48bcf52b648675","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/fbb64e54134ccd8306d022e4bf48bcf52b648675","comments_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/fbb64e54134ccd8306d022e4bf48bcf52b648675/comments","author":{"login":"rueiyhuang","id":134524501,"node_id":"U_kgDOCASuVQ","avatar_url":"https://avatars.githubusercontent.com/u/134524501?v=4","gravatar_id":"","url":"https://api.github.com/users/rueiyhuang","html_url":"https://github.com/rueiyhuang","followers_url":"https://api.github.com/users/rueiyhuang/followers","following_url":"https://api.github.com/users/rueiyhuang/following{/other_user}","gists_url":"https://api.github.com/users/rueiyhuang/gists{/gist_id}","starred_url":"https://api.github.com/users/rueiyhuang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rueiyhuang/subscriptions","organizations_url":"https://api.github.com/users/rueiyhuang/orgs","repos_url":"https://api.github.com/users/rueiyhuang/repos","events_url":"https://api.github.com/users/rueiyhuang/events{/privacy}","received_events_url":"https://api.github.com/users/rueiyhuang/received_events","type":"User","user_view_type":"public","site_admin":false},"committer":{"login":"rueiyhuang","id":134524501,"node_id":"U_kgDOCASuVQ","avatar_url":"https://avatars.githubusercontent.com/u/134524501?v=4","gravatar_id":"","url":"https://api.github.com/users/rueiyhuang","html_url":"https://github.com/rueiyhuang","followers_url":"https://api.github.com/users/rueiyhuang/followers","following_url":"https://api.github.com/users/rueiyhuang/following{/other_user}","gists_url":"https://api.github.com/users/rueiyhuang/gists{/gist_id}","starred_url":"https://api.github.com/users/rueiyhuang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rueiyhuang/subscriptions","organizations_url":"https://api.github.com/users/rueiyhuang/orgs","repos_url":"https://api.github.com/users/rueiyhuang/repos","events_url":"https://api.github.com/users/rueiyhuang/events{/privacy}","received_events_url":"https://api.github.com/users/rueiyhuang/received_events","type":"User","user_view_type":"public","site_admin":false},"parents":[{"sha":"b08497046600dd2f950f29f7cc3d1d67265e38ce","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/b08497046600dd2f950f29f7cc3d1d67265e38ce","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/b08497046600dd2f950f29f7cc3d1d67265e38ce"}]},{"sha":"2b8397650dede09c609343e567ef3794f84a8662","node_id":"C_kwDOEOee_NoAKDJiODM5NzY1MGRlZGUwOWM2MDkzNDNlNTY3ZWYzNzk0Zjg0YTg2NjI","commit":{"author":{"name":"Ruei-Yang Huang","email":"ryhuang@amazon.com","date":"2026-05-18T20:06:55Z"},"committer":{"name":"Ruei-Yang Huang","email":"ryhuang@amazon.com","date":"2026-05-18T20:07:29Z"},"message":"Update CHANGELOG","tree":{"sha":"4d5bd1d3a4fd88b78ea7746181fbd0403fc1b82d","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/trees/4d5bd1d3a4fd88b78ea7746181fbd0403fc1b82d"},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/git/commits/2b8397650dede09c609343e567ef3794f84a8662","comment_count":0,"verification":{"verified":false,"reason":"unsigned","signature":null,"payload":null,"verified_at":null}},"url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/2b8397650dede09c609343e567ef3794f84a8662","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/2b8397650dede09c609343e567ef3794f84a8662","comments_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/2b8397650dede09c609343e567ef3794f84a8662/comments","author":{"login":"rueiyhuang","id":134524501,"node_id":"U_kgDOCASuVQ","avatar_url":"https://avatars.githubusercontent.com/u/134524501?v=4","gravatar_id":"","url":"https://api.github.com/users/rueiyhuang","html_url":"https://github.com/rueiyhuang","followers_url":"https://api.github.com/users/rueiyhuang/followers","following_url":"https://api.github.com/users/rueiyhuang/following{/other_user}","gists_url":"https://api.github.com/users/rueiyhuang/gists{/gist_id}","starred_url":"https://api.github.com/users/rueiyhuang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rueiyhuang/subscriptions","organizations_url":"https://api.github.com/users/rueiyhuang/orgs","repos_url":"https://api.github.com/users/rueiyhuang/repos","events_url":"https://api.github.com/users/rueiyhuang/events{/privacy}","received_events_url":"https://api.github.com/users/rueiyhuang/received_events","type":"User","user_view_type":"public","site_admin":false},"committer":{"login":"rueiyhuang","id":134524501,"node_id":"U_kgDOCASuVQ","avatar_url":"https://avatars.githubusercontent.com/u/134524501?v=4","gravatar_id":"","url":"https://api.github.com/users/rueiyhuang","html_url":"https://github.com/rueiyhuang","followers_url":"https://api.github.com/users/rueiyhuang/followers","following_url":"https://api.github.com/users/rueiyhuang/following{/other_user}","gists_url":"https://api.github.com/users/rueiyhuang/gists{/gist_id}","starred_url":"https://api.github.com/users/rueiyhuang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rueiyhuang/subscriptions","organizations_url":"https://api.github.com/users/rueiyhuang/orgs","repos_url":"https://api.github.com/users/rueiyhuang/repos","events_url":"https://api.github.com/users/rueiyhuang/events{/privacy}","received_events_url":"https://api.github.com/users/rueiyhuang/received_events","type":"User","user_view_type":"public","site_admin":false},"parents":[{"sha":"fbb64e54134ccd8306d022e4bf48bcf52b648675","url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/commits/fbb64e54134ccd8306d022e4bf48bcf52b648675","html_url":"https://github.com/aws/amazon-redshift-python-driver/commit/fbb64e54134ccd8306d022e4bf48bcf52b648675"}]}],"files":[{"sha":"ce612947a3492a7d5eb86f9434afc033fe0b0eb4","filename":"CHANGELOG.md","status":"modified","additions":7,"deletions":0,"changes":7,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/CHANGELOG.md","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/CHANGELOG.md","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/CHANGELOG.md?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -1,6 +1,13 @@\n Changelog\n =========\n \n+v2.1.14 (2026-05-18)\n+-------------------\n+- Added support for pg_catalog internal data types in the getFunctionColumns and getProcedureColumns metadata APIs.\n+- Addressed security issue as detailed in CVE-2026-41066\n+- Addressed security issue as detailed in CVE-2026-8838\n+\n+\n v2.1.13 (2026-03-30)\n -------------------\n - Raised minimum supported Python version from 3.6 to 3.7"},{"sha":"186767172e5f2eab3c9d1801a5f8a5e3de2b1a60","filename":"README.rst","status":"modified","additions":1,"deletions":1,"changes":2,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/README.rst","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/README.rst","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/README.rst?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -7,7 +7,7 @@ redshift_connector\n .. |PyPi| image:: https://img.shields.io/pypi/v/redshift_connector.svg?maxAge=432000&style=flat-square\n    :target: https://pypi.org/project/redshift_connector/\n \n-.. |Python Version| image:: https://img.shields.io/badge/python->=3.7-brightgreen.svg\n+.. |Python Version| image:: https://img.shields.io/badge/python->=3.8-brightgreen.svg\n    :target: https://pypi.org/project/redshift_connector/\n \n ``redshift_connector`` is the Amazon Redshift connector for"},{"sha":"ba1eb033c36bd4326e7da761763cfc3ce95e6183","filename":"redshift_connector/metadataAPIHelper.py","status":"modified","additions":35,"deletions":2,"changes":37,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/redshift_connector%2FmetadataAPIHelper.py","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/redshift_connector%2FmetadataAPIHelper.py","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/redshift_connector%2FmetadataAPIHelper.py?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -74,7 +74,7 @@ class RedshiftDataTypes:\n         'double precision', 'float8', 'float',\n \n         # Character types\n-        'char', 'character', 'nchar', 'bpchar',\n+        'char', '\"char\"', 'character', 'nchar', 'bpchar',\n         'varchar', 'character varying', 'nvarchar', 'text',\n \n         # Date/Time types\n@@ -85,6 +85,7 @@ class RedshiftDataTypes:\n         'timestamptz', 'timestamp with time zone',\n         'intervaly2m', 'interval year to month',\n         'intervald2s', 'interval day to second',\n+        'interval',\n \n         # Other types\n         'boolean', 'bool',\n@@ -99,7 +100,39 @@ class RedshiftDataTypes:\n         'smallint[]',\n         'pg_attribute',\n         'pg_type',\n-        'refcursor'\n+        'refcursor',\n+\n+        # pg_catalog pseudo-types\n+        '\"any\"', '\"trigger\"', '\"unknown\"', 'anyelement', 'anyarray',\n+        'record', 'void', 'opaque', 'language_handler',\n+\n+        # pg_catalog network/address types\n+        'inet', 'cidr', 'macaddr',\n+\n+        # pg_catalog legacy time types\n+        'abstime', 'reltime', 'tinterval',\n+\n+        # pg_catalog ACL and system catalog types\n+        'aclitem', 'aclitem[]', 'oid[]', 'oidvector', 'int2vector',\n+\n+        # pg_catalog registration types\n+        'regproc', 'regprocedure', 'regoper', 'regoperator', 'regclass', 'regtype',\n+\n+        # pg_catalog system/internal types\n+        'smgr', 'tid', 'xid', 'cid', 'cstring',\n+\n+        # pg_catalog geometric types\n+        'box', 'circle', 'line', 'lseg', '\"path\"', 'point', 'polygon',\n+\n+        # pg_catalog monetary/binary/misc types\n+        'money', 'bit', 'bit varying', 'bytea', 'name',\n+\n+        # Redshift-specific internal types\n+        'pyobject', 'roleitem', 'useritem',\n+\n+        # pg_catalog array types\n+        'bigint[]', 'double precision[]', 'numeric[]',\n+        'interval[]', 'intervaly2m[]', 'intervald2s[]',\n     }\n \n     @classmethod"},{"sha":"6eb18f99ef2d29ff5a89bc7dfb598d42e4f20bc9","filename":"redshift_connector/utils/type_utils.py","status":"modified","additions":4,"deletions":21,"changes":25,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/redshift_connector%2Futils%2Ftype_utils.py","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/redshift_connector%2Futils%2Ftype_utils.py","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/redshift_connector%2Futils%2Ftype_utils.py?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -83,7 +83,10 @@ def int2_recv(data: bytes, offset: int, length: int) -> int:\n \n \n def vector_in(data: bytes, idx: int, length: int) -> typing.List:\n-    return eval(\"[\" + data[idx : idx + length].decode(_client_encoding).replace(\" \", \",\") + \"]\")\n+    text = data[idx : idx + length].decode(_client_encoding).strip()\n+    if not text:\n+        return []\n+    return [int(x) for x in text.split()]\n \n \n def int4_recv(data: bytes, offset: int, length: int) -> int:\n@@ -222,26 +225,6 @@ def intervald2s_send_integer(v: IntervalDayToSecond) -> bytes:\n     return typing.cast(bytes, q_pack(microseconds))\n \n \n-glbls: typing.Dict[str, type] = {\"Decimal\": Decimal}\n-trans_tab = dict(zip(map(ord, \"{}\"), \"[]\"))\n-\n-\n-# def array_in(data: bytes, idx: int, length: int) -> typing.List:\n-#     arr: typing.List[str] = []\n-#     prev_c = None\n-#     for c in data[idx:idx + length].decode(\n-#             _client_encoding).translate(\n-#         trans_tab).replace('NULL', 'None'):\n-#         if c not in ('[', ']', ',', 'N') and prev_c in ('[', ','):\n-#             arr.extend(\"Decimal('\")\n-#         elif c in (']', ',') and prev_c not in ('[', ']', ',', 'e'):\n-#             arr.extend(\"')\")\n-#\n-#         arr.append(c)\n-#         prev_c = c\n-#     return typing.cast(typing.List, eval(''.join(arr), glbls))\n-\n-\n def numeric_in_binary(data: bytes, offset: int, length: int, scale: int) -> Decimal:\n     raw_value: int\n "},{"sha":"198855a9eec52f823d141bbe1f778b436db5a27a","filename":"redshift_connector/version.py","status":"modified","additions":1,"deletions":1,"changes":2,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/redshift_connector%2Fversion.py","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/redshift_connector%2Fversion.py","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/redshift_connector%2Fversion.py?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -2,4 +2,4 @@\n # 1) we don't load dependencies by storing it in __init__.py\n # 2) we can import it in setup.py for the same reason\n # 3) we can import it into your module module\n-__version__ = \"2.1.13\"\n+__version__ = \"2.1.14\""},{"sha":"1b2dd6da03e298176677ef4617e8d34a5c3bca98","filename":"requirements.txt","status":"modified","additions":1,"deletions":1,"changes":2,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/requirements.txt","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/requirements.txt","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/requirements.txt?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -3,7 +3,7 @@ pytz>=2020.1\n beautifulsoup4>=4.13.5,<5.0.0\n boto3>=1.42.22,<2.0.0\n requests>=2.23.0,<3.0.0\n-lxml>=4.6.5,<=6.0.2\n+lxml>=6.1.0,<7.0.0\n botocore>=1.12.201,<2.0.0\n packaging\n setuptools"},{"sha":"d6e2a9267390ad9d2051108c039aa09120a9eac8","filename":"setup.py","status":"modified","additions":1,"deletions":2,"changes":3,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/setup.py","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/setup.py","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/setup.py?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -118,7 +118,7 @@ def get_tag(self):\n     author_email=\"redshift-drivers@amazon.com\",\n     url=\"https://github.com/aws/amazon-redshift-python-driver\",\n     license=\"Apache License 2.0\",\n-    python_requires=\">=3.7\",\n+    python_requires=\">=3.8\",\n     install_requires=open(\"requirements.txt\").read().strip().split(\"\\n\"),\n     extras_require=optional_deps,\n     classifiers=[\n@@ -127,7 +127,6 @@ def get_tag(self):\n         \"License :: OSI Approved :: BSD License\",\n         \"Programming Language :: Python\",\n         \"Programming Language :: Python :: 3\",\n-        \"Programming Language :: Python :: 3.7\",\n         \"Programming Language :: Python :: 3.8\",\n         \"Programming Language :: Python :: 3.9\",\n         \"Programming Language :: Python :: 3.10\","},{"sha":"04e82f3a0eca9ef26db24c3c6078057e3583f607","filename":"test/integration/metadata/test_metadataAPI_functions.py","status":"modified","additions":40,"deletions":0,"changes":40,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/test%2Fintegration%2Fmetadata%2Ftest_metadataAPI_functions.py","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/test%2Fintegration%2Fmetadata%2Ftest_metadataAPI_functions.py","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/test%2Fintegration%2Fmetadata%2Ftest_metadataAPI_functions.py?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -102,11 +102,13 @@ class FunctionColumnInfo:\n     FunctionColumnInfo(current_catalog, test_schema_1, test_func_1, \"test_column_smallint\", FunctionColumnType.IN, 5, \"int2\", 5, 2, 0, 10, 2, \"\", None, 1, \"\", test_func_1_specific_name),\n     FunctionColumnInfo(current_catalog, test_schema_1, test_func_1, \"test_column_integer\", FunctionColumnType.IN, 4, \"int4\", 10, 4, 0, 10, 2, \"\", None, 2, \"\", test_func_1_specific_name),\n     FunctionColumnInfo(current_catalog, test_schema_1, test_func_1, \"test_column_bigint\", FunctionColumnType.IN, -5, \"int8\", 19, 20, 0, 10, 2, \"\", None, 3, \"\", test_func_1_specific_name),\n+    # RedCat-2542\n     # SQL UDF has an issue where precision and scale was not stored and returned properly for numeric data type\n     FunctionColumnInfo(current_catalog, test_schema_1, test_func_1, \"test_column_numeric\", FunctionColumnType.IN, 2, \"numeric\", 0, None, 0, 10, 2, \"\", None, 4, \"\", test_func_1_specific_name),\n     FunctionColumnInfo(current_catalog, test_schema_1, test_func_1, \"test_column_real\", FunctionColumnType.IN, 7, \"float4\", 8, 4, 8, 10, 2, \"\", None, 5, \"\", test_func_1_specific_name),\n     FunctionColumnInfo(current_catalog, test_schema_1, test_func_1, \"test_column_double\", FunctionColumnType.IN, 8, \"float8\", 17, 8, 17, 10, 2, \"\", None, 6, \"\", test_func_1_specific_name),\n     FunctionColumnInfo(current_catalog, test_schema_1, test_func_1, \"test_column_boolean\", FunctionColumnType.IN, -7, \"bool\", 1, 1, 0, 10, 2, \"\", None, 7, \"\", test_func_1_specific_name),\n+    # RedCat-2542\n     # SQL UDF has an issue where character_maximum_length was not stored and returned properly for char/varchar data type\n     FunctionColumnInfo(current_catalog, test_schema_1, test_func_1, \"test_column_char\", FunctionColumnType.IN, 1, \"char\", 0, None, 0, 10, 2, \"\", None, 8, \"\", test_func_1_specific_name),\n     FunctionColumnInfo(current_catalog, test_schema_1, test_func_1, \"test_column_varchar\", FunctionColumnType.IN, 12, \"varchar\", 0, None, 0, 10, 2, \"\", None, 9, \"\", test_func_1_specific_name),\n@@ -205,3 +207,41 @@ def get_function_columns_matches(catalog, schema, function, column) -> typing.Li\n                     (pattern_matches(column, func_col_info.column_name))):\n                 result.append(func_col_info)\n         return result\n+\n+\n+class TestMetadataAPIFunctionsPgCatalog:\n+    \"\"\"\n+    Tests that get_functions and get_function_columns support\n+    pg_catalog functions whose argument lists contain internal PostgreSQL\n+    data types (e.g., inet, cstring, aclitem[], pyobject).\n+\n+    We only verify the metadata API does not error out for pg_catalog schema.\n+    No result validation is performed since the server blocks system function\n+    column discovery (SHOW PARAMETERS OF FUNCTION returns empty for system functions).\n+    \"\"\"\n+\n+    @pytest.mark.skip(reason=\"Server currently hide pg_catalog in SHOW SCHEMAS result\")\n+    def test_get_functions_pg_catalog(self, db_kwargs) -> None:\n+        \"\"\"get_functions for pg_catalog schema should succeed and return rows.\"\"\"\n+        with redshift_connector.connect(**db_kwargs) as conn:\n+            cursor = conn.cursor()\n+            result: tuple = cursor.get_functions(None, \"pg_catalog\", None)\n+            assert len(result) > 0, \"Expected at least one function from pg_catalog\"\n+\n+    def test_get_function_columns_pg_catalog(self, db_kwargs) -> None:\n+        \"\"\"get_function_columns for pg_catalog schema should not throw.\n+        Just iterate results to confirm no error during processing.\"\"\"\n+        with redshift_connector.connect(**db_kwargs) as conn:\n+            cursor = conn.cursor()\n+            # This should not raise even though pg_catalog functions use\n+            # internal types like inet, cstring, aclitem[], pyobject, etc.\n+            result: tuple = cursor.get_function_columns(None, \"pg_catalog\", None, None)\n+            # no-op: we only care that no exception is thrown\n+\n+    @pytest.mark.skip(reason=\"Server currently blocks system function column discovery for pg_catalog\")\n+    def test_get_function_columns_pg_catalog_abbrev(self, db_kwargs) -> None:\n+        \"\"\"get_function_columns for pg_catalog.abbrev (inet arg) should return rows.\"\"\"\n+        with redshift_connector.connect(**db_kwargs) as conn:\n+            cursor = conn.cursor()\n+            result: tuple = cursor.get_function_columns(None, \"pg_catalog\", \"abbrev\", None)\n+            assert len(result) > 0, \"Expected at least one column row for pg_catalog.abbrev\""},{"sha":"8352352447e6abf269cbabaaaec4c85e760e8027","filename":"test/integration/test_idp_token_auth_integration.py","status":"added","additions":554,"deletions":0,"changes":554,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/test%2Fintegration%2Ftest_idp_token_auth_integration.py","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/test%2Fintegration%2Ftest_idp_token_auth_integration.py","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/test%2Fintegration%2Ftest_idp_token_auth_integration.py?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -0,0 +1,554 @@\n+\"\"\"\n+Integration tests for IdpTokenAuthPlugin with identity enhanced credentials. In order to get the credentials and setup\n+for these tests, we perform the following:\n+1. Python Driver Prod account tod role has permissions to assume EspressoRedshiftRole in drivers testing account\n+   EspressoRedshiftRole has all of the necessary permissions to perform the actions for this test\n+2. Using EspressoRedshiftRole's credentials, we will get a JWT token, use CreateTokenWIthIAM to get identity context, and then assume\n+   role with the identity context in order to get the identity enhanced AWS credentials that we can use to run these integration tests\n+\n+In order to get the identity enhanced credentials, we use the Azure TTI set up with IdC for the drivers testing account to get a JWT token\n+, which we then call CreateTokenWithIAM with to get the associated identity context. We then call assume role with the identity context\n+in order to get the identity enhanced credentials.\n+\n+Cluster endpoints are stored in the secret manager and have been onboarded to an IdC application with the EspressoRedshiftRole created in\n+Python Driver Prod account. We have also created test_user_azure user in identity center for positive test cases authentication.\n+\"\"\"\n+\n+import json\n+from typing import Any, Dict, Optional\n+import pytest\n+import requests\n+import boto3\n+from botocore.exceptions import ClientError\n+\n+import redshift_connector\n+\n+\n+class AzureAuthenticator:\n+    \"\"\"Handles Azure AD authentication and AWS credential exchange using boto3.\n+\n+    Uses boto3 SDK for all AWS API calls, eliminating subprocess/CLI dependency.\n+    \"\"\"\n+\n+    # Secret name in AWS Secrets Manager\n+    PROD_SECRET_NAME = \"IdpToken-Python-Testing-Credentials\"\n+    SECRET_NAME = \"test/smus-tip-credentials\"\n+    SECRET_REGION = \"us-east-1\"\n+\n+    def __init__(self):\n+        # Fields for IDC\n+        self.iam_role = self._get_assume_role_arn()\n+        self.region = \"us-east-1\"\n+\n+        # boto3 clients with assumed role credentials\n+        self._sts_client = None\n+        self._secretsmanager_client = None\n+        self._sso_oidc_client = None\n+\n+        # Step 1: Assume base role to get credentials for subsequent AWS API calls\n+        self._assume_base_role()\n+\n+        # Step 2: Fetch secrets using assumed role credentials from testing account\n+        secrets = self._get_secrets()\n+\n+        self.idc_app_arn = secrets['idc_app_arn']\n+        self.TEST_AZURE_TENANT_ID = secrets['azure_tenant_id']\n+        self.TEST_AZURE_APP_ID = secrets['azure_app_id']\n+        self.TEST_AZURE_SCOPE = secrets['azure_scope']\n+        self.TEST_AZURE_CLIENT_SECRET = secrets['azure_client_secret']\n+        self.username = secrets['username']\n+        self.user_password = secrets['password']\n+\n+        # Redshift endpoints from secrets\n+        self.provisioned_endpoint = secrets['provisioned_endpoint']\n+        self.serverless_endpoint = secrets['serverless_endpoint']\n+\n+    def _get_assume_role_arn(self) -> str:\n+        \"\"\"Fetch the role arn from secret manager\"\"\"\n+        session = boto3.session.Session()\n+        client = session.client(service_name=\"secretsmanager\", region_name=self.SECRET_REGION)\n+        try:\n+            response = client.get_secret_value(SecretId=self.PROD_SECRET_NAME)\n+        except ClientError as e:\n+            raise e\n+        return json.loads(response['SecretString'])[\"role_arn\"]\n+\n+    def _assume_base_role(self) -> None:\n+        \"\"\"Assume EspressoRedshiftRole to get base credentials for AWS API calls.\n+\n+        Uses boto3 default credential chain, then creates new clients\n+        with the assumed role credentials.\n+        \"\"\"\n+        try:\n+            # Use default credential chain for initial STS client\n+            sts = boto3.client('sts', region_name=self.region)\n+\n+            response = sts.assume_role(\n+                RoleArn=self.iam_role,\n+                RoleSessionName='integration-test-session'\n+            )\n+            creds = response['Credentials']\n+\n+            # Create boto3 clients with assumed role credentials\n+            self._sts_client = boto3.client(\n+                'sts',\n+                region_name=self.region,\n+                aws_access_key_id=creds['AccessKeyId'],\n+                aws_secret_access_key=creds['SecretAccessKey'],\n+                aws_session_token=creds['SessionToken']\n+            )\n+\n+            self._secretsmanager_client = boto3.client(\n+                'secretsmanager',\n+                region_name=self.SECRET_REGION,\n+                aws_access_key_id=creds['AccessKeyId'],\n+                aws_secret_access_key=creds['SecretAccessKey'],\n+                aws_session_token=creds['SessionToken']\n+            )\n+\n+            self._sso_oidc_client = boto3.client(\n+                'sso-oidc',\n+                region_name=self.region,\n+                aws_access_key_id=creds['AccessKeyId'],\n+                aws_secret_access_key=creds['SecretAccessKey'],\n+                aws_session_token=creds['SessionToken']\n+            )\n+\n+            print(f\"✓ Assumed base role (expires: {creds['Expiration']})\")\n+\n+        except ClientError as e:\n+            print(f\"Failed to assume base role: {e}\")\n+            raise\n+\n+    def _get_secrets(self) -> Dict[str, str]:\n+        \"\"\"Fetch Azure credentials from AWS Secrets Manager using boto3.\"\"\"\n+        try:\n+            response = self._secretsmanager_client.get_secret_value(\n+                SecretId=self.SECRET_NAME\n+            )\n+            return json.loads(response['SecretString'])\n+        except ClientError as e:\n+            print(f\"Failed to fetch secrets from Secrets Manager: {e}\")\n+            raise\n+\n+    def get_azure_token(self):\n+        try:\n+            url = f'https://login.microsoftonline.com/{self.TEST_AZURE_TENANT_ID}/oauth2/v2.0/token'\n+\n+            data_payload = {\n+                'client_id': self.TEST_AZURE_APP_ID,\n+                'scope': self.TEST_AZURE_SCOPE,\n+                'grant_type': 'password',\n+                'username': self.username,\n+                'password': self.user_password,\n+                'client_secret': self.TEST_AZURE_CLIENT_SECRET\n+            }\n+\n+            resp = requests.post(url, data=data_payload)\n+            resp.raise_for_status()\n+            resp_json = json.loads(resp.text)\n+            return resp_json['access_token']\n+\n+        except requests.exceptions.RequestException as e:\n+            print(f\"HTTP Request failed: {e}\")\n+            raise\n+        except json.JSONDecodeError as e:\n+            print(f\"Failed to parse JSON response: {e}\")\n+            raise\n+        except KeyError as e:\n+            print(f\"Access token not found in response: {e}\")\n+            raise\n+\n+    def assume_role_with_context(self, context_assertion: str) -> Dict[str, Any]:\n+        \"\"\"Assume IAM role with identity context to get identity-enhanced credentials.\"\"\"\n+        try:\n+            response = self._sts_client.assume_role(\n+                RoleArn=self.iam_role,\n+                RoleSessionName='integration-test-session',\n+                ProvidedContexts=[{\n+                    'ProviderArn': 'arn:aws:iam::aws:contextProvider/IdentityCenter',\n+                    'ContextAssertion': context_assertion\n+                }]\n+            )\n+            return response\n+        except ClientError as e:\n+            print(f\"AWS STS assume-role with context failed: {e}\")\n+            raise\n+\n+    def create_aws_token(self, azure_token: str) -> Dict[str, Any]:\n+        \"\"\"Exchange Azure token for AWS token with identity context using boto3.\"\"\"\n+        try:\n+            response = self._sso_oidc_client.create_token_with_iam(\n+                clientId=self.idc_app_arn,\n+                grantType='urn:ietf:params:oauth:grant-type:jwt-bearer',\n+                assertion=azure_token\n+            )\n+            return response\n+        except ClientError as e:\n+            print(f\"AWS SSO-OIDC create_token_with_iam failed: {e}\")\n+            raise\n+\n+\n+class TestIdpTokenAuthPlugin:\n+    \"\"\"Test class for IdpTokenAuthPlugin integration tests.\"\"\"\n+\n+    # Cluster configuration constants\n+    DATABASE = \"dev\"\n+    REGION = \"us-east-1\"\n+\n+    # Cached credentials and endpoints (class-level to avoid re-fetching)\n+    _credentials: Optional[Dict[str, str]] = None\n+    _provisioned_host: Optional[str] = None\n+    _serverless_host: Optional[str] = None\n+\n+    @classmethod\n+    def setup_credentials(cls):\n+        \"\"\"Fetch and cache AWS credentials using Azure authentication flow.\n+\n+        Credentials are cached at class level to avoid re-fetching during test session.\n+        \"\"\"\n+        # Check if credentials are already cached\n+        if cls._credentials is not None:\n+            print(\"✓ Using cached credentials\")\n+            return\n+\n+        authenticator = AzureAuthenticator()\n+\n+        # Cache endpoints from secrets\n+        cls._provisioned_host = authenticator.provisioned_endpoint\n+        cls._serverless_host = authenticator.serverless_endpoint\n+\n+        # Step 1: Get Azure token\n+        azure_token = authenticator.get_azure_token()\n+        print(\"✓ Obtained Azure token\")\n+\n+        # Step 2: Exchange Azure token for AWS token with identity context\n+        aws_response = authenticator.create_aws_token(azure_token)\n+        print(\"✓ Got AWS token with identity context\")\n+\n+        # Step 3: Assume role with context to get temporary credentials\n+        context_assertion = aws_response['awsAdditionalDetails']['identityContext']\n+        credentials_response = authenticator.assume_role_with_context(context_assertion)\n+        print(\"✓ Assumed role successfully\")\n+\n+        # Extract and cache credentials\n+        creds = credentials_response['Credentials']\n+        cls._credentials = {\n+            'access_key_id': creds['AccessKeyId'],\n+            'secret_access_key': creds['SecretAccessKey'],\n+            'session_token': creds['SessionToken'],\n+            'expiration': creds['Expiration']\n+        }\n+\n+        print(f\"✓ Credentials cached (expires: {creds['Expiration']})\")\n+\n+    def get_connection_params(self, host: str = None):\n+        \"\"\"Build connection parameters for the given host.\n+\n+        Args:\n+            host: The Redshift host to connect to. If None, defaults to provisioned host.\n+\n+        Returns:\n+            dict: Connection parameters for redshift_connector.connect()\n+        \"\"\"\n+        # Ensure credentials are fetched and cached\n+        if self._credentials is None:\n+            self.setup_credentials()\n+\n+        # Default to provisioned host if not specified\n+        if host is None:\n+            host = self._provisioned_host\n+\n+        return {\n+            \"host\": host,\n+            \"database\": self.DATABASE,\n+            \"credentials_provider\": \"IdpTokenAuthPlugin\",\n+            \"access_key_id\": self._credentials['access_key_id'],\n+            \"secret_access_key\": self._credentials['secret_access_key'],\n+            \"session_token\": self._credentials['session_token'],\n+        }\n+\n+    def _get_host_for_type(self, host_type: str) -> str:\n+        \"\"\"Get the host URL for the given cluster type.\n+\n+        Args:\n+            host_type: Either \"provisioned\" or \"serverless\"\n+\n+        Returns:\n+            str: The host URL for the specified cluster type\n+        \"\"\"\n+        # Ensure credentials/endpoints are fetched\n+        if self._credentials is None:\n+            self.setup_credentials()\n+\n+        if host_type == \"provisioned\":\n+            return self._provisioned_host\n+        elif host_type == \"serverless\":\n+            return self._serverless_host\n+        else:\n+            raise ValueError(f\"Unknown host_type: {host_type}\")\n+\n+    @pytest.mark.parametrize(\"host_type\", [\"provisioned\", \"serverless\"])\n+    def test_connect_and_execute_select_one(self, host_type: str):\n+        \"\"\"Test connecting to Redshift and executing SELECT 1.\n+\n+        This test validates that IdpTokenAuthPlugin successfully connects to both\n+        provisioned clusters and serverless workgroups using identity-enhanced credentials.\n+\n+        \"\"\"\n+        host = self._get_host_for_type(host_type)\n+        conn = redshift_connector.connect(**self.get_connection_params(host))\n+\n+        try:\n+            cursor = conn.cursor()\n+            cursor.execute(\"SELECT 1\")\n+            result = cursor.fetchone()\n+\n+            assert result[0] == 1, f\"Expected SELECT 1 to return 1, got {result[0]}\"\n+            print(f\"✓ Successfully connected to {host_type} cluster and executed SELECT 1\")\n+\n+            cursor.close()\n+        finally:\n+            conn.close()\n+\n+    @pytest.mark.parametrize(\"host_type\", [\"provisioned\", \"serverless\"])\n+    def test_connect_and_query_current_user(self, host_type: str):\n+        \"\"\"Test connecting to Redshift and querying current user.\n+\n+        This test validates that after successful authentication, the connection\n+        has a valid user context and can retrieve the current user information.\n+\n+        \"\"\"\n+        host = self._get_host_for_type(host_type)\n+        conn = redshift_connector.connect(**self.get_connection_params(host))\n+\n+        try:\n+            cursor = conn.cursor()\n+            cursor.execute(\"SELECT current_user\")\n+            result = cursor.fetchone()\n+\n+            assert result is not None, \"Expected current_user query to return a result\"\n+            assert result[0] is not None, \"Expected current_user to not be None\"\n+            assert len(result[0]) > 0, \"Expected current_user to not be empty\"\n+            print(f\"✓ Successfully connected to {host_type} cluster, current_user: {result[0]}\")\n+\n+            cursor.close()\n+        finally:\n+            conn.close()\n+\n+    @pytest.mark.parametrize(\"host_type\", [\"provisioned\", \"serverless\"])\n+    def test_connect_and_execute_multiple_queries(self, host_type: str):\n+        \"\"\"Test executing multiple queries on the same cursor.\n+\n+        This test validates that a connection established via IdpTokenAuthPlugin\n+        can execute multiple queries sequentially on the same cursor without issues.\n+\n+        \"\"\"\n+        host = self._get_host_for_type(host_type)\n+        conn = redshift_connector.connect(**self.get_connection_params(host))\n+\n+        try:\n+            cursor = conn.cursor()\n+\n+            # Execute first query\n+            cursor.execute(\"SELECT 1\")\n+            result1 = cursor.fetchone()\n+            assert result1[0] == 1, f\"First query failed: expected 1, got {result1[0]}\"\n+\n+            # Execute second query\n+            cursor.execute(\"SELECT 2 + 2\")\n+            result2 = cursor.fetchone()\n+            assert result2[0] == 4, f\"Second query failed: expected 4, got {result2[0]}\"\n+\n+            # Execute third query\n+            cursor.execute(\"SELECT current_database()\")\n+            result3 = cursor.fetchone()\n+            assert result3[0] is not None, \"Third query failed: expected database name\"\n+\n+            print(f\"✓ Successfully executed 3 queries on {host_type} cluster\")\n+\n+            cursor.close()\n+        finally:\n+            conn.close()\n+\n+    # ==================== Invalid Credentials Failure Tests ====================\n+\n+    def test_invalid_access_key_id_fails(self):\n+        \"\"\"Test that connection fails when AccessKeyId is invalid.\n+\n+        This test validates that IdpTokenAuthPlugin properly fails when provided\n+        with an invalid AccessKeyId. The error originates from the AWS API call\n+        (GetIdentityCenterAuthToken) and is wrapped in an InterfaceError.\n+\n+        \"\"\"\n+        # Get valid connection params and replace AccessKeyId with invalid value\n+        params = self.get_connection_params(self._provisioned_host)\n+        params['access_key_id'] = 'INVALID_ACCESS_KEY_ID_12345'\n+\n+        with pytest.raises(\n+            redshift_connector.InterfaceError,\n+            match=\"IdC authentication failed: Failed to obtain token from GetIdentityCenterAuthToken\"\n+        ):\n+            conn = redshift_connector.connect(**params)\n+            # If connection somehow succeeds, try to execute a query to trigger auth failure\n+            cursor = conn.cursor()\n+            cursor.execute(\"SELECT 1\")\n+            cursor.close()\n+            conn.close()\n+\n+    def test_invalid_secret_access_key_fails(self):\n+        \"\"\"Test that connection fails when SecretAccessKey is invalid.\n+\n+        This test validates that IdpTokenAuthPlugin properly fails when provided\n+        with an invalid SecretAccessKey. The error originates from the AWS API call\n+        (GetIdentityCenterAuthToken) and is wrapped in an InterfaceError.\n+\n+        \"\"\"\n+        # Get valid connection params and replace SecretAccessKey with invalid value\n+        params = self.get_connection_params(self._provisioned_host)\n+        params['secret_access_key'] = 'INVALID_SECRET_ACCESS_KEY_12345'\n+\n+        with pytest.raises(\n+            redshift_connector.InterfaceError,\n+            match=\"IdC authentication failed: Failed to obtain token from GetIdentityCenterAuthToken\"\n+        ):\n+            conn = redshift_connector.connect(**params)\n+            # If connection somehow succeeds, try to execute a query to trigger auth failure\n+            cursor = conn.cursor()\n+            cursor.execute(\"SELECT 1\")\n+            cursor.close()\n+            conn.close()\n+\n+    def test_invalid_session_token_fails(self):\n+        \"\"\"Test that connection fails when SessionToken is invalid.\n+\n+        This test validates that IdpTokenAuthPlugin properly fails when provided\n+        with an invalid SessionToken. The error originates from the AWS API call\n+        (GetIdentityCenterAuthToken) and is wrapped in an InterfaceError.\n+\n+        \"\"\"\n+        # Get valid connection params and replace SessionToken with invalid value\n+        params = self.get_connection_params(self._provisioned_host)\n+        params['session_token'] = 'INVALID_SESSION_TOKEN_12345'\n+\n+        with pytest.raises(\n+            redshift_connector.InterfaceError,\n+            match=\"IdC authentication failed: Failed to obtain token from GetIdentityCenterAuthToken\"\n+        ):\n+            conn = redshift_connector.connect(**params)\n+            # If connection somehow succeeds, try to execute a query to trigger auth failure\n+            cursor = conn.cursor()\n+            cursor.execute(\"SELECT 1\")\n+            cursor.close()\n+            conn.close()\n+\n+    # ==================== Missing Parameters Failure Tests ====================\n+\n+    def test_missing_access_key_id_fails(self):\n+        \"\"\"Test that connection fails when AccessKeyId is missing.\n+\n+        This test validates that IdpTokenAuthPlugin properly fails when\n+        AccessKeyId is omitted from connection parameters. Without all three\n+        identity-enhanced credential params, and without direct token params,\n+        the plugin raises an error indicating neither auth flow is satisfied.\n+\n+        \"\"\"\n+        # Build params without access_key_id - use dummy values for other params\n+        # since validation happens before any AWS API calls\n+        params = {\n+            \"host\": \"dummy-host.redshift.amazonaws.com\",\n+            \"database\": self.DATABASE,\n+            \"credentials_provider\": \"IdpTokenAuthPlugin\",\n+            \"secret_access_key\": \"dummy_secret_access_key\",\n+            \"session_token\": \"dummy_session_token\",\n+        }\n+\n+        with pytest.raises(\n+            redshift_connector.InterfaceError,\n+            match=\"Either token/token_type or AccessKeyID/SecretAccessKey/SessionToken must be provided\"\n+        ):\n+            redshift_connector.connect(**params)\n+\n+    def test_missing_secret_access_key_fails(self):\n+        \"\"\"Test that connection fails when SecretAccessKey is missing.\n+\n+        This test validates that IdpTokenAuthPlugin properly fails when\n+        SecretAccessKey is omitted from connection parameters. Without all three\n+        identity-enhanced credential params, and without direct token params,\n+        the plugin raises an error indicating neither auth flow is satisfied.\n+\n+        \"\"\"\n+        # Build params without secret_access_key - use dummy values for other params\n+        # since validation happens before any AWS API calls\n+        params = {\n+            \"host\": \"dummy-host.redshift.amazonaws.com\",\n+            \"database\": self.DATABASE,\n+            \"credentials_provider\": \"IdpTokenAuthPlugin\",\n+            \"access_key_id\": \"dummy_access_key_id\",\n+            \"session_token\": \"dummy_session_token\",\n+        }\n+\n+        with pytest.raises(\n+            redshift_connector.InterfaceError,\n+            match=\"Either token/token_type or AccessKeyID/SecretAccessKey/SessionToken must be provided\"\n+        ):\n+            redshift_connector.connect(**params)\n+\n+    def test_missing_session_token_fails(self):\n+        \"\"\"Test that connection fails when SessionToken is missing.\n+\n+        This test validates that IdpTokenAuthPlugin properly fails when\n+        SessionToken is omitted from connection parameters. Without all three\n+        identity-enhanced credential params, and without direct token params,\n+        the plugin raises an error indicating neither auth flow is satisfied.\n+\n+        \"\"\"\n+        # Build params without session_token - use dummy values for other params\n+        # since validation happens before any AWS API calls\n+        params = {\n+            \"host\": \"dummy-host.redshift.amazonaws.com\",\n+            \"database\": self.DATABASE,\n+            \"credentials_provider\": \"IdpTokenAuthPlugin\",\n+            \"access_key_id\": \"dummy_access_key_id\",\n+            \"secret_access_key\": \"dummy_secret_access_key\",\n+        }\n+\n+        with pytest.raises(\n+            redshift_connector.InterfaceError,\n+            match=\"Either token/token_type or AccessKeyID/SecretAccessKey/SessionToken must be provided\"\n+        ):\n+            redshift_connector.connect(**params)\n+\n+    # ==================== Conflicting Parameters Failure Tests ====================\n+\n+    def test_conflicting_token_and_credentials_params_fails(self):\n+        \"\"\"Test that connection fails when both token/token_type AND identity-enhanced credentials are provided.\n+\n+        This test validates that IdpTokenAuthPlugin properly fails when conflicting\n+        authentication parameters are provided. The plugin should detect that both\n+        direct token parameters (token, token_type) and identity-enhanced credentials\n+        (access_key_id, secret_access_key, session_token) are provided and raise an error.\n+\n+        The validation happens locally before any AWS API calls, so no real credentials needed.\n+\n+        \"\"\"\n+        # Build params with BOTH token/token_type AND identity-enhanced credentials\n+        # This is a conflicting configuration that should be rejected\n+        params = {\n+            \"host\": \"dummy-host.redshift.amazonaws.com\",\n+            \"database\": self.DATABASE,\n+            \"credentials_provider\": \"IdpTokenAuthPlugin\",\n+            # Direct token parameters\n+            \"token\": \"dummy_direct_token\",\n+            \"token_type\": \"ACCESS_TOKEN\",\n+            # Identity-enhanced credentials parameters\n+            \"access_key_id\": \"dummy_access_key_id\",\n+            \"secret_access_key\": \"dummy_secret_access_key\",\n+            \"session_token\": \"dummy_session_token\",\n+        }\n+\n+        with pytest.raises(\n+            redshift_connector.InterfaceError,\n+            match=\"Cannot provide both direct token parameters \\\\(token, token_type\\\\) and \\\\(AccessKeyID, SecretAccessKey, SessionToken\\\\)\"\n+        ):\n+            redshift_connector.connect(**params)"},{"sha":"94d36c61cc16003db23aacac02487640920b8538","filename":"test/performance/protocol_performance.py","status":"modified","additions":1,"deletions":1,"changes":2,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/test%2Fperformance%2Fprotocol_performance.py","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/test%2Fperformance%2Fprotocol_performance.py","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/test%2Fperformance%2Fprotocol_performance.py?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -11,7 +11,7 @@\n \"\"\"\n THIS IS A MANUAL TEST REQUIRING LEADER NODE ACCESS ON A REDSHIFT CLUSTER\n 1) Execute protocol_perf_test.sql, using a tool like psql, on your Redshift cluster\n-2) Install Python>=3.7 on the leader node of your Redshift cluster and install redshift_connector\n+2) Install Python>=3.8 on the leader node of your Redshift cluster and install redshift_connector\n 3) Hardcode user, password, password arguments for connect(...). Ensure host is set to 'localhost' and SSL is\n    disabled.\n 4) Execute this script from the leader node, the script will output performance results"},{"sha":"ca8c328c9ea3098317c12f0a2f56845527fdabde","filename":"test/unit/test_metadataAPIHelper.py","status":"modified","additions":128,"deletions":0,"changes":128,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/test%2Funit%2Ftest_metadataAPIHelper.py","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/test%2Funit%2Ftest_metadataAPIHelper.py","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/test%2Funit%2Ftest_metadataAPIHelper.py?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -769,3 +769,131 @@ def test_consecutive_wildcards(metadata_helper):\n     assert metadata_helper.pattern_match(\"hello\", \"h%_%o\")\n     assert metadata_helper.pattern_match(\"hello\", \"h_%_%o\")\n     assert metadata_helper.pattern_match(\"hello\", \"h%_%_%o\")\n+\n+\n+# -------------------------------------------------------------------------\n+# pg_catalog internal data type tests\n+# -------------------------------------------------------------------------\n+\n+PG_CATALOG_TYPES = [\n+    # Pseudo-types (quoted reserved words)\n+    '\"any\"', '\"trigger\"', '\"unknown\"', 'anyelement', 'anyarray',\n+    'record', 'void', 'opaque', 'language_handler',\n+    # Network/address types\n+    'inet', 'cidr', 'macaddr',\n+    # Legacy time types\n+    'abstime', 'reltime', 'tinterval',\n+    # ACL and system catalog types\n+    'aclitem', 'aclitem[]', 'oid[]', 'oidvector', 'int2vector',\n+    # Registration types\n+    'regproc', 'regprocedure', 'regoper', 'regoperator', 'regclass', 'regtype',\n+    # System/internal types\n+    'smgr', 'tid', 'xid', 'cid', 'cstring',\n+    # Geometric types\n+    'box', 'circle', 'line', 'lseg', '\"path\"', 'point', 'polygon',\n+    # Monetary/binary/misc types\n+    'money', 'bit', 'bit varying', 'bytea', 'name',\n+    # Redshift-specific internal types\n+    'pyobject', 'roleitem', 'useritem',\n+    # Array types\n+    'bigint[]', 'double precision[]', 'numeric[]',\n+    'interval[]', 'intervaly2m[]', 'intervald2s[]',\n+]\n+\n+\n+from redshift_connector.metadataAPIHelper import RedshiftDataTypes\n+\n+\n+@pytest.mark.parametrize(\"data_type\", PG_CATALOG_TYPES)\n+def test_pg_catalog_type_is_valid(data_type: str):\n+    \"\"\"Each pg_catalog internal type should be accepted by is_valid_type.\"\"\"\n+    assert RedshiftDataTypes.is_valid_type(data_type), f\"Type should be valid: {data_type}\"\n+\n+\n+@pytest.mark.parametrize(\"data_type\", sorted(RedshiftDataTypes.VALID_TYPES))\n+def test_all_valid_types_accepted(data_type: str):\n+    \"\"\"Every type in VALID_TYPES should be accepted by is_valid_type.\"\"\"\n+    assert RedshiftDataTypes.is_valid_type(data_type), f\"Type from VALID_TYPES should be valid: {data_type}\"\n+\n+\n+@pytest.mark.parametrize(\"data_type\", sorted(RedshiftDataTypes.VALID_TYPES))\n+def test_all_valid_types_parameterized_query(metadata_helper, data_type: str):\n+    \"\"\"createParameterizedQueryString should accept every type in VALID_TYPES.\"\"\"\n+    sql, args = metadata_helper.create_parameterized_query_string(\n+        data_type, \"SHOW PARAMETERS OF FUNCTION %s.%s.%s\", None\n+    )\n+    assert len(args) == 1, f\"Should have 1 arg for type: {data_type}\"\n+    assert \"%s\" in sql, f\"Query should contain placeholder for type: {data_type}\"\n+\n+\n+@pytest.mark.parametrize(\"data_type\", PG_CATALOG_TYPES)\n+def test_pg_catalog_type_parameterized_query(metadata_helper, data_type: str):\n+    \"\"\"createParameterizedQueryString should accept each pg_catalog type without raising.\"\"\"\n+    sql, args = metadata_helper.create_parameterized_query_string(\n+        data_type, \"SHOW PARAMETERS OF FUNCTION %s.%s.%s\", None\n+    )\n+    assert len(args) == 1\n+    assert \"%s\" in sql\n+\n+\n+def test_pg_catalog_mixed_types_parameterized_query(metadata_helper):\n+    \"\"\"createParameterizedQueryString should accept a mix of pg_catalog types.\"\"\"\n+    arg_list = \"inet, cstring, aclitem[], regproc, \\\"any\\\"\"\n+    sql, args = metadata_helper.create_parameterized_query_string(\n+        arg_list, \"SHOW PARAMETERS OF FUNCTION %s.%s.%s\", None\n+    )\n+    assert len(args) == 5\n+\n+\n+def test_pg_catalog_with_standard_types(metadata_helper):\n+    \"\"\"createParameterizedQueryString should accept pg_catalog types mixed with standard types.\"\"\"\n+    arg_list = \"integer, inet, varchar, cstring\"\n+    sql, args = metadata_helper.create_parameterized_query_string(\n+        arg_list, \"SHOW PARAMETERS OF FUNCTION %s.%s.%s\", None\n+    )\n+    assert len(args) == 4\n+\n+\n+def test_standard_types_still_valid():\n+    \"\"\"Standard Redshift types should still be accepted after the fix.\"\"\"\n+    for t in [\"integer\", \"varchar\", \"boolean\", \"double precision\", \"timestamp\", \"date\", \"numeric\"]:\n+        assert RedshiftDataTypes.is_valid_type(t), f\"Standard type should be valid: {t}\"\n+\n+\n+def test_legacy_types_still_valid():\n+    \"\"\"Legacy types should still be accepted after the fix.\"\"\"\n+    for t in [\"oid\", \"smallint[]\", \"pg_attribute\", \"pg_type\", \"refcursor\"]:\n+        assert RedshiftDataTypes.is_valid_type(t), f\"Legacy type should be valid: {t}\"\n+\n+\n+def test_invalid_types_still_rejected():\n+    \"\"\"Invalid/malicious types should still be rejected.\"\"\"\n+    for t in [\"not_a_real_type\", \"integer; DROP TABLE\", \"' OR 1=1 --\", \"faketype\"]:\n+        assert not RedshiftDataTypes.is_valid_type(t), f\"Invalid type should be rejected: {t}\"\n+\n+\n+def test_invalid_type_raises(metadata_helper):\n+    \"\"\"createParameterizedQueryString should raise for invalid types.\"\"\"\n+    with pytest.raises(ValueError):\n+        metadata_helper.create_parameterized_query_string(\n+            \"integer, not_a_real_type\", \"SHOW PARAMETERS OF FUNCTION %s.%s.%s\", None\n+        )\n+\n+\n+def test_case_insensitive_validation():\n+    \"\"\"Type validation should be case-insensitive.\"\"\"\n+    assert RedshiftDataTypes.is_valid_type(\"INET\")\n+    assert RedshiftDataTypes.is_valid_type(\"Cstring\")\n+    assert RedshiftDataTypes.is_valid_type(\"MACADDR\")\n+    assert RedshiftDataTypes.is_valid_type(\"Regproc\")\n+\n+\n+def test_quoted_char_type_valid():\n+    \"\"\"Both quoted and unquoted char should be valid.\"\"\"\n+    assert RedshiftDataTypes.is_valid_type('\"char\"')\n+    assert RedshiftDataTypes.is_valid_type('char')\n+\n+\n+def test_standalone_interval_valid():\n+    \"\"\"Standalone 'interval' should be valid (was previously missing).\"\"\"\n+    assert RedshiftDataTypes.is_valid_type('interval')"},{"sha":"5cd4d094c19d15054108d12098ccf27a7159bd92","filename":"test/unit/test_type_utils.py","status":"modified","additions":41,"deletions":0,"changes":41,"blob_url":"https://github.com/aws/amazon-redshift-python-driver/blob/2b8397650dede09c609343e567ef3794f84a8662/test%2Funit%2Ftest_type_utils.py","raw_url":"https://github.com/aws/amazon-redshift-python-driver/raw/2b8397650dede09c609343e567ef3794f84a8662/test%2Funit%2Ftest_type_utils.py","contents_url":"https://api.github.com/repos/aws/amazon-redshift-python-driver/contents/test%2Funit%2Ftest_type_utils.py?ref=2b8397650dede09c609343e567ef3794f84a8662","patch":"@@ -84,3 +84,44 @@ def test_timestamp_recv_integer(_input) -> None:\n     print(type_utils.timestamp_recv_integer(in_val, 0, 0))\n     print(EPOCH.timestamp() * 1000)\n     assert type_utils.timestamp_recv_integer(in_val, 0, 0) == exp_val\n+\n+\n+# --- vector_in tests ---\n+\n+vector_in_normal_data: typing.List[typing.Tuple[bytes, typing.List[int]]] = [\n+    (b\"1 2 3\", [1, 2, 3]),\n+    (b\"1\", [1]),\n+    (b\"0\", [0]),\n+    (b\"-1\", [-1]),\n+    (b\"-32768\", [-32768]),\n+    (b\"32767\", [32767]),\n+    (b\"-1 2 -3\", [-1, 2, -3]),\n+    (b\"1 0 3\", [1, 0, 3]),\n+    (b\"\", []),\n+]\n+\n+\n+@pytest.mark.parametrize(\"_input\", vector_in_normal_data)\n+def test_vector_in_normal(_input) -> None:\n+    \"\"\"Verify vector_in correctly parses space-separated int16 values.\"\"\"\n+    data, expected = _input\n+    result = type_utils.vector_in(data, 0, len(data))\n+    assert result == expected\n+    for val in result:\n+        assert isinstance(val, int)\n+\n+\n+vector_in_injection_payloads: typing.List[bytes] = [\n+    b\"__import__('os').system('echo exploited')\",\n+    b\"__import__('os').uname().sysname\",\n+    b\"__import__('subprocess').check_output(['whoami'])\",\n+    b\"open('/etc/passwd').read()\",\n+    b\"exec('import os')\",\n+]\n+\n+\n+@pytest.mark.parametrize(\"payload\", vector_in_injection_payloads)\n+def test_vector_in_rejects_code_injection(payload) -> None:\n+    \"\"\"Verify vector_in raises an exception for non-integer input instead of executing it.\"\"\"\n+    with pytest.raises((ValueError, TypeError)):\n+        type_utils.vector_in(payload, 0, len(payload))"}]}