1- // examples/simple_query_with_mtls.rs
1+ // example/simple_query_with_mtls.rs
2+ // Example demonstrating using PgwireLite with mutual TLS (mTLS)
23
3- use pgwire_lite:: PgwireLite ;
4+ use colorize:: AnsiColor ;
5+ use pgwire_lite:: { PgwireLite , Value } ;
46use std:: env;
57use std:: path:: PathBuf ;
68
7- fn main ( ) {
8- // Get the home directory and properly construct paths
9+ fn print_heading ( title : & str ) {
10+ let title_owned = title. to_string ( ) ; // Convert &str to String
11+ println ! ( "{}" , title_owned. blue( ) . bold( ) ) ;
12+ }
13+
14+ // Pretty print a row with formatting
15+ fn print_row ( row : & std:: collections:: HashMap < String , Value > , index : usize ) {
16+ if index == 0 {
17+ // Print header
18+ println ! ( "Row {}: {{" , index) ;
19+ } else {
20+ println ! ( "\n Row {}: {{" , index) ;
21+ }
22+
23+ for ( key, value) in row {
24+ println ! (
25+ " {}: {}" ,
26+ key. clone( ) . green( ) ,
27+ format!( "{}" , value) . yellow( )
28+ ) ;
29+ }
30+ println ! ( "}}" ) ;
31+ }
32+
33+ fn execute_query ( conn : & PgwireLite , query : & str ) {
34+ match conn. query ( query) {
35+ Ok ( result) => {
36+ println ! ( ) ;
37+
38+ println ! ( "Elapsed time: {} ms" , result. elapsed_time_ms) ;
39+
40+ println ! ( "Result status: {:?}" , result. status) ;
41+
42+ println ! (
43+ "{} columns, {} rows, {} notices" ,
44+ result. col_count, result. row_count, result. notice_count
45+ ) ;
46+
47+ if !result. column_names . is_empty ( ) {
48+ println ! ( "Column names: {:?}" , result. column_names) ;
49+ }
50+
51+ if !result. rows . is_empty ( ) {
52+ println ! ( "Data:" ) ;
53+ for ( i, row) in result. rows . iter ( ) . enumerate ( ) {
54+ print_row ( row, i) ;
55+ }
56+ }
57+
58+ if !result. notices . is_empty ( ) {
59+ println ! ( "Notices (detail):" ) ;
60+ for notice in result. notices . iter ( ) {
61+ if let Some ( detail) = notice. fields . get ( "detail" ) {
62+ println ! ( "{}" , detail) ;
63+ }
64+ }
65+ }
66+ println ! ( ) ;
67+ }
68+ Err ( e) => eprintln ! ( "Error: {}" , e) ,
69+ }
70+ }
71+
72+ fn setup_tls ( ) {
73+ // Set up environment variables for TLS
974 let home_dir = env:: var ( "HOME" ) . expect ( "Could not find HOME environment variable" ) ;
1075 let ssl_dir = PathBuf :: from ( & home_dir) . join ( "ssl-test" ) ;
11-
12- // Set environment variables with absolute paths
13- env:: set_var ( "PGSSLMODE" , "verify-full " ) ;
76+
77+ // Configure TLS settings
78+ env:: set_var ( "PGSSLMODE" , "verify-ca " ) ; // Use verify-ca instead of verify-full to bypass hostname check
1479 env:: set_var (
1580 "PGSSLCERT" ,
1681 ssl_dir
@@ -29,14 +94,80 @@ fn main() {
2994 . to_string_lossy ( )
3095 . to_string ( ) ,
3196 ) ;
97+
98+ // Disable hostname verification for testing purposes
99+ env:: set_var ( "PGSSLSNI" , "0" ) ;
100+ }
32101
33- // Create the connection with SSL enabled
34- let conn =
35- PgwireLite :: new ( "localhost" , 5444 , true , "verbose" ) . expect ( "Failed to create connection" ) ;
102+ fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
103+ env_logger:: init ( ) ;
104+
105+ // Setup TLS environment variables
106+ setup_tls ( ) ;
36107
37- // Try to execute a simple query
38- match conn. query ( "SELECT 1 as col_name" ) {
39- Ok ( result) => println ! ( "Query result (TLS): {:?}" , result) ,
40- Err ( e) => eprintln ! ( "Error: {}" , e) ,
41- }
42- }
108+ // Create a connection configuration with TLS enabled
109+ // Using IP address instead of hostname to avoid certificate validation issues
110+ let conn = PgwireLite :: new ( "127.0.0.1" , 5444 , true , "verbose" ) ?;
111+
112+ println ! ( ) ;
113+ println ! ( "libpq version: {}" , conn. libpq_version( ) ) ;
114+ println ! ( "Verbosity set to: {}" , conn. verbosity( ) ) ;
115+ println ! ( "TLS connection: Enabled" ) ;
116+ println ! ( ) ;
117+
118+ //
119+ // registry list example
120+ //
121+ print_heading ( "REGISTRY LIST example" ) ;
122+ execute_query ( & conn, "REGISTRY LIST aws" ) ;
123+
124+ //
125+ // registry pull examples
126+ //
127+ print_heading ( "REGISTRY PULL examples" ) ;
128+ execute_query ( & conn, "REGISTRY PULL homebrew" ) ;
129+
130+ //
131+ // simple select with one row
132+ //
133+ print_heading ( "Literal SELECT example (one row)" ) ;
134+ execute_query ( & conn, "SELECT 1 as col_name" ) ;
135+
136+ //
137+ // simple select with no rows
138+ //
139+ print_heading ( "Literal SELECT example (no rows)" ) ;
140+ execute_query ( & conn, "SELECT 1 as col_name WHERE 1=0" ) ;
141+
142+ //
143+ // failed command - handle expected error
144+ //
145+ print_heading ( "Failed command example" ) ;
146+ execute_query ( & conn, "NOTACOMMAND" ) ;
147+
148+ //
149+ // stackql provider select, multiple rows
150+ //
151+ print_heading ( "StackQL SELECT example (multiple rows)" ) ;
152+ execute_query (
153+ & conn,
154+ "SELECT * FROM homebrew.formula.vw_usage_metrics WHERE formula_name IN ('stackql','steampipe')" ,
155+ ) ;
156+
157+ //
158+ // stackql provider select, provider error, no rows
159+ //
160+ print_heading ( "StackQL SELECT example with provider error and no rows" ) ;
161+ execute_query ( & conn, "SELECT id, name, description, stargazers_count FROM github.repos.repos WHERE org = 'nonexistent-org'" ) ;
162+
163+ //
164+ // another stackql provider select, should succeed
165+ //
166+ print_heading ( "StackQL SELECT example" ) ;
167+ execute_query (
168+ & conn,
169+ "SELECT * FROM homebrew.formula.vw_info WHERE formula_name = 'stackql'" ,
170+ ) ;
171+
172+ Ok ( ( ) )
173+ }
0 commit comments