Repository: diesel-rs/diesel
File: diesel/src/pg/connection/stmt/mod.rs (Rust)

Code before:
                param_formats: vec![1; param_types.len()],
                sql: Some(sql_cstr),
                param_types: Some(param_types_vec),
            });
        }

        // For named/cached statements, prepare as usual
        let internal_result = unsafe {
            let param_count: libc::c_int = param_types
                .len()
                .try_into()
                .map_err(|e| crate::result::Error::SerializationError(Box::new(e)))?;
            raw_connection.prepare(
                name_cstr.as_ptr(),
                sql_cstr.as_ptr(),
                param_count,
                param_types_to_ptr(Some(&param_types_vec)),
            )
        };
        PgResult::new(internal_result?, raw_connection)?;

        Ok(Statement {
            name: name_cstr,
            param_formats: vec![1; param_types.len()],
            sql: None,
            param_types: None,
        })
    }
}

fn param_types_to_ptr(param_types: Option<&Vec<u32>>) -> *const pq_sys::Oid {
    param_types
        .map(|types| types.as_ptr())
        .unwrap_or(ptr::null())
}


Review comment (refactor):
Could we refactor this code a bit to better use the following pattern:

```
if let Some(name) = name {
   // do named statement stuff here
} else {
   // do unnamed stuff here
}
```

That would at least initializing the name with nothing.

Also it might be worth to introduce an enum 

```rust
enum StatementKind {
    Unnamed {sql: CString, param_types: Vec<_>},
    Named {name: CString}
}
```

to better group data that belong together. This enum could be used as a second field inside of `Statement` beside the `param_formats` field which is always the same for all statements.

Code after:
            PrepareForCache::Yes { counter } => {
                // For named/cached statements, prepare as usual using a prepare phase and then
                // an execute phase
                let name_cstr = CString::new(format!("__diesel_stmt_{counter}"))?;
                let internal_result = unsafe {
                    let param_count: libc::c_int = param_types
                        .len()
                        .try_into()
                        .map_err(|e| crate::result::Error::SerializationError(Box::new(e)))?;
                    raw_connection.prepare(
                        name_cstr.as_ptr(),
                        sql_cstr.as_ptr(),
                        param_count,
                        param_types_vec.as_ptr(),
                    )
                };
                PgResult::new(internal_result?, raw_connection)?;

                Ok(Statement {
                    kind: StatementKind::Named { name: name_cstr },
                    param_formats: vec![1; param_types.len()],
                })
            }
            PrepareForCache::No => {
                // For unnamed statements, we'll return a Statement object without
                // actually preparing it. This allows us to use send_query_params
                // later in the execute call. This is needed to better interface
                // with PgBouncer which cannot handle unnamed prepared statements
                // when those are prepared and executed in separate transactions.
                // See https://github.com/diesel-rs/diesel/pull/4539
                Ok(Statement {
                    kind: StatementKind::Unnamed {
                        sql: sql_cstr,
                        param_types: param_types_vec,
                    },
                    param_formats: vec![1; param_types.len()],
                })
            }
        }
    }
}