Correct behavior of libpq's PQexecPrepared and SQL EXECUTE - sql

It looks like with postgres, there are two ways to prepare and execute prepared statements. You can use the functions PQprepare and PQexecPrepared directly from libpq; or you can issue SQL statements: PREPARE and EXECUTE. The statement names are the same across either method so you can use PQPrepare to prepare a statement and then execute it by issuing an EXECUTE query (or use a PREPARE query and then execute it with PQexecPrepared).
So the two approaches (library functions vs SQL queries) are equivalent. However, it looks like when you use PQexecPrepared, the query column of pg_stat_activity is the underlying prepared statement with placeholders. So something like:
SELECT * from users where name in ($1, $2, $3);
But when you use an EXECUTE query, pg_stat_activity contains the SQL of the EXECUTE, like:
EXECUTE user_query('joe', 'bob', 'sally');
Questions
Is there a way to get the same output for the two different ways of executing prepared statements?
Is there a way to see both the query, and the bound parameters when executing prepared statements?

You are right that both ways to execute a prepared statement do the same thing under the hood, but since they are called in different ways on the SQL level, they look different in pg_stat_activity. There is no way to change that.
To get the statement and the parameters you must resort to the log file.
In the case of PQexecPrepared, you will see the statement as a LOG message and the parameters as its DETAIL if you turn on statement logging.
With PREPARE and EXECUTE, you have no choice but to find the PREPARE earlier in the session (both have the same session identifier, that is %c in log_line_prefix).

Related

Procedure - Dynamic where conditions

I have a procedure, based on the parameters, the where condition would differ.
The OUT parameters have to be INTO clause so that I can return the columns from the procedure.
Rather than having SQL condition for each if condition, what is the efficient way of doing this.
It looks to me more like a design question.
So it depends on what you need to achieve and how you want to organize your code.
Possibilities
1- your "if" chain of queries in the same procedure
2- one procedure for each query
3 - if the differencies between the "where" parts are not so big use sql constructs, including unions, case , and\or etc to let coexist different cases in one query
4- build sql dynamically and use execute immediate
Usually i don't like the 1, i would try with 3 or 4, then proceed with 2 if i can't.
EDIT
With dynamic sql, for getting out results you can do
EXECUTE IMMEDIATE stmt into o_total_count,o_total_sum,o_hold_status,o_normal_status;
In case you have input params for the query, you have to mark them with : and then add the USING clause with the appropriate input param.
Example
EXECUTE IMMEDIATE 'select count(*) from departments where department_id=:id' INTO l_cnt USING l_dept_id;

Dynamic queries with format() using the same argument many times

I have a procedure which takes as input a suffix of a table's name. Then, using execute format(), I pass this parameter to execute the dynamic query. The problem is that this parameter is the same throughout - I do not want to pass it x times as such:
execute format('SELECT table_%s.field1, table_%s.field2,table_%s.field3
FROM table_%s', inTableSuffix, inTableSuffix, inTableSuffix, inTableSuffix, ...)
I would like a format similar to the following:
execute format('SELECT table_%s.field1, table_%s.field2,table_%s.field3
FROM table_%s', inTableSuffix)
I understand that I can solve this problem using an alias to the table name but is there another alternative?
You can repeatedly address the positional arguments like this:
execute format('SELECT table_%1$s.field1
, table_%1$s.field2,table_%1$s.field3
FROM table_%1$s;', inTableSuffix);
Note: in this particular case, you can avoid repeating yourself by using an alias:
execute format('SELECT tx.field1
, tx.field2, tx.field3
FROM table_%s tx;', inTableSuffix);
#wildplasser already provided the syntax how to reference the same parameter repeatedly in format(). The code is still dangerous, though. You need to escape identifiers built from user input:
EXECUTE format('SELECT field1, field2, field3 FROM %I', 'table_' || inTableSuffix);
For the given example, you only need the parameter once anyway. The scope of dynamic queries executed with EXECUTE in plpgsql is limited to the query itself. Other variables or parameters of the function are not visible inside EXECUTE. Hence, there is not need to table-qualify columns in a dynamic query with a single table in the FROM clause.
But more importantly, %I is used in format() for identifiers to avoid syntax errors, misguided lower-casing or, worse, SQL injection! It double-quotes (only!) otherwise illegal identifiers, just like quote_ident() would.
Details:
SQL injection in Postgres functions vs prepared queries
Demonstrate SQL injection in PL/pgSQL
Are PostgreSQL column names case-sensitive?

Batching heterogeneous SQL prepared statements with Groovy?

Batch insert using groovy Sql? discusses how to execute multiple prepared statements in a batch. But all the statements must have the same structure (passed in as a top-level argument to withBatch).
Is there a way to batch up heterogeneous prepared statements like:
sql.withBatch {ps ->
ps.addBatch("insert into t1 values(:a, :b)", [a:1, b:2])
ps.addBatch("insert into t2 values(:c)", [c:3])
}
(This throws an exception because addBatch doesn't have that signature.)
As described in Oracle's documentation:
Prepared statements:
The same statement is repeated with different bind variables.
Batch updates:
You can reduce the number of round-trips to the database, thereby improving application performance, by grouping multiple UPDATE, DELETE, or INSERT statements into a single batch and having the whole batch sent to the database and processed in one trip. This is especially useful in combination with a prepared statement.
As described in IBM's documentation and taken from here:
The JDBC drivers that support JDBC 2.0 and above support batch
updates. With batch updates, instead of updating rows of a DB2(R)
table one at a time, you can direct JDBC to execute a group of updates
at the same time. Statements that can be included in the same batch of
updates are known as batchable statements.
If a statement has input parameters or host expressions, you can
include that statement only in a batch that has other instances of the
same statement. This type of batch is known as a homogeneous batch. If
a statement has no input parameters, you can include that statement in
a batch only if the other statements in the batch have no input
parameters or host expressions. This type of batch is known as a
heterogeneous batch. Two statements that can be included in the same
batch are known as batch compatible.
This means that your request is not possible. The only advantage you can get is performance improvement of batching the same type of statements AND preparing only once:
When you execute a single SQL statement the database performs the following actions:
prepare the statement
bind the parameters
execute the statement
When you use batch commands the following happens:
prepare the statement (all received in a single transmission)
for all following identical statements with different parameters
bind the parameters
execute the statement
Since the preparation is performed only once you save time.
But you can sort and split the commands:
sql.withBatch(20, "insert into t1 values(:a, :b)") {
...
}
sql.withBatch(20, "insert into t2 values(:c)") {
...
}
BTW, what will compile is
sql.withBatch {ps ->
ps.addBatch("insert into t1 values(1, 2)")
ps.addBatch("insert into t2 values(3)")
}
But in this case I am curious what will happen: I expect that the JDBC driver will simply not use batching.
For this example, consider writing a stored procedure for your database (docs) that takes three parameters and inserts both records. Your application can call the procedure with a single prepared statement, and the statement could be batched.

Sybase - Stored procedure - Store results of a SQL query into an OUTPUT parameter

In a stored procedure, I've to build my own SQL request(because tables names and some properties names are known only at execution time(parameters)).
So Basically I've something like this
EXECUTE IMMEDIATE WITH RESULT SET OFF 'My custom query which select one data'
Usually, I would use the INTO commands, but my parameter is recognized inside the Execute immediate, which seems logic.
(Before you ask: I cannot return this in a result set, the result set is used for another data(and the result of this EXECUTE IMMEDIATE will determine which query I will run(and must be returned)).
How would you approach this problem? I guess it's the same problem on SQL Server-... but I didn't tested on it
You could create a table in compiled Sql and then the dynamic Sql populates it, so that the compiled sql statement after the dynamic part can read the results and update them onto your output params.

What are prepared statements? How are they different from dynamic sql?

I did not see any duplicate questions but wondering if somebody can provide some good examples and specially best practices around these.
Prepared Statements are precompiled statements that you can run multiple times against on the database, and SQLServer won't parse or generate a different execution plan each time you run it. Usually, you run prepared statement in a client context (using JDBC, ADO.NET, ODBC or any other client access technology).
A prepared statement in Java (using JDBC, of course) will be something like:
PreparedStatement ps = conn.prepareStatmente("insert into t(field1) values (?)");
ps.setString(1, "Hello");
ps.executeUpdate();
ps.setStrgin(2, "World");
ps.executeUpdate();
ps.close();
// two rows will be inserted into table t:
// field1 => "Hello"
// field1 => "world"
Dynamic SQL is the ability to run any SQL sentence stored in a dynamic variable (i.e. a string) inside a stored procedure or function in SQLServer. You can find some examples in the link provided.
It'd be easier to explain with some context...
In Java, PreparedStatements are SQL statements in a Java String and supports placeholders you can populate without worrying about escaping single quotes. .NET also has PreparedStatement syntax:
Prepared execution is commonly used by applications to execute the same parameterized SQL statement repeatedly. Prepared execution is faster than direct execution for statements executed more than three or four times because the statement is compiled only once, while statements executed directly are compiled each time they are executed. Prepared execution can also provide a reduction in network traffic because the driver can send an execution plan identifier and the parameter values, rather than an entire SQL statement, to the data source each time the statement is executed.
A step short of using a Stored Procedure...
MySQL's dynamic SQL syntax is also called PreparedStatements...
Dynamic SQL
Dynamic SQL is basically any SQL declared as a string data type - it can be customized before execution. The need for using dynamic SQL comes when you want to do things like dynamic column and/or table references. For example, no SQL supports a string variable to represent the table in the FROM clause (Table Valued Variables are an exception, where supported).
It's important to know the difference between EXEC and EXEC sp_executesql with regard to dynamic SQL on SQL Server. EXEC sp_executesql was added in SQL Server 2005, and you can read more about dynamic SQL on SQL Server in the excellent article: The Curse and Blessings of Dynamic SQL
PreparedStaement is a language construct that provides pre-compiled queries that has already been explained in above answers. One very important benefit of using prepared statements is that they save you from malicious SQL injection attacks. How? you only have placeholder in which you can put in values and no other way to alter the query (pre-compiled), whereas in case of Statements, you can alter the query string. Example:
I have a query to update a table -
UPDATE table_name SET col1 = 40 WHERE id = 'A001';
This can be altered (maliciously) as -
UPDATE table_name SET col1 = 40 WHERE id = 'A001'; DROP TABLE table_name;
And your table is gone!
Dynamic queries are a database construct that helps you to write a query in which you can use bind variables rather using values. These are particularly used in PL/SQL code. Also useful in executing DDL statements. Example code (Oracle):
ip_job_name := 'APP_EXTRACT';
lv_query := 'SELECT 1 FROM user_table WHERE table_name = :tab_name';
BEGIN
EXECUTE IMMEDIATE lv_query INTO lv_tab USING ip_job_name;
EXECUTE IMMEDIATE 'DROP TABLE ' || ip_job_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;