I'm developing a plpgsql function that takes a couple parameters and expect those to follow a specific format. Is there a standard place where I could/should document the function behavior in order to make it user friendly?
You can attach COMMENT strings to various database objects.
That said, a simple SQL comment at the top of your function body might stand a better chance of actually being read by future developers.
Related
So I have a PG function create_order (language is PL/PGSQL) which accepts a quite a few arguments.
I have noticed that every time I modify argument name, its type, or if I add a new argument, I have to drop the function (CREATE OR REPLACE does not work)
So I have been thinking what if I just accept one single argument of type jsonb and call it day...So the signature would look like create_order(args jsonb)
My questions are
is this considered bad practice in PG "world" (affects performance or some other aspect) or bad practice from a programming standpoint
if #1 is bad approach, would it better to create custom composite type and use it as an argument to a function?
I don't see a big problem with a jsonb function parameter, except maybe that individual parameters make it more obvious what the input values are. But that's nothing that can't be fixed with documentation.
On the other hand, I also see no problem with dropping and recreating functions when the signature changes. It may serve as a reminder that calling sites need to be updated.
I'd say that you should go with the approach that fits you and the problem at hand best – it does not matter from the PostgreSQL point of view.
I am using the Firebird ADO.NET Data Provider and before I pass the reader on to a consuming service I would like to determine whether any rows were returned. Consider the following snippet:
FbCommand cmd = GetSomeCommandFromTheEther();
FbDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
DoSomethingWith(reader);
else
TellTheUserWeGotNothing();
What I've now learned is that FbDataReader.HasRows always returns True. In fact looking at the source code it would appear it is just a wrapper for FbDataReader.command.IsSelectCommand, not only useless, it makes the property name "HasRows" a complete misnomer.
In any event, how can I find out whether a given query has rows, without advancing the record pointer? Note that I want to pass the reader off to an external service; if I call FbDataReader.Read() to check its result, I will consume a row and DoSomethingWith() will not get this first row.
I am afraid you have stumbled on a Firebird limitation. As stated in following Firebird FAQ link:
Why FbDataReader.HasRows returns always true?
The FbDataReader.HasRows property is implemented for compatibility
only. It returns always true because Firebird doesn't have a way for
know if a query returns rows of not without fetching the data.
There is already a mention of this in the Firebird Tracker. Check the issue DNET-305.
On the other hand, in .NET, it seems OleDbDataReader and SqlDataReader, which inherit from DbDataReader have the same problem, as stated in this MSDN link.
Since FbDataReader inherits from the same class as those, you might want to consider one of the workarounds that Microsoft suggests in its MSDN article, which is to perform first a select count(*). Granted, that is unelegant and a waste of time and resources but at least it could help you out.
I’m just starting to convert all of my site’s code into prepared statements for that extra security cushion but I find myself running into the same questions.
After some reading, I’ve decided to use prepared statements on all select queries, however I’m not sure if all of variables in these queries require to be used as “parameters” in the prepared statement.
For example:
Where some_column IS NULL
Where some_column = $_SESSION[‘some-session-var’]
Where some_column IN ($someArray)
Also, is there some way to give each condition a “name” rather than using the question mark? I feel like I’ve seen this before in documentation, but I’ve had no luck finding it since.
For example: Where city_name = :cityName. If so, how would I go about binding the parameters here?
Thanks,
Evan
Yes. All data going to the query should be added via placeholders.
Otherwise there will be no security at all.
Though prepared statements extremely limited and support only scalar values, so, your first and third examples require extra coding (examples can be found in plenty under the tag)
Named placeholders you mentioned belongs to PDO, mysqli don't support them
In an effort to adhere to the Dry Principle I have some code I feel could easily live in a function. I may need to reuse this code at some point in the future, I may not. Ideally I would have a function that lives just in this piece of code as it provides no benefit to the database as a whole and living inside any of the existing scheme's will create noise when trying to find meaningful and globally useful functions.
I have tried to write a script which uses typical syntax to create a function before my other code and drop the function at the end of the code. This is less than ideal because of potential collisions in the future, but an acceptable risk. Unfortunately I get an error:
'CREATE FUNCTION' must be the first statement in a query batch.
Adding semi-colons before and after the statement unfortunately is not a quick fix. Is there no way to quickly to use functions without building them into the framework of the database?
Or am I asking the wrong question. Is there a way in one script to force separate batches?
If you're truly running a "batch" (e.g. a set of T-SQL commands run in Query analyzer or ossql), then simply use "go". Your "create function" should work if it's the first line after a "go" - again, depending on your T-SQL interpreter. OSSQL: should work. An ADO connection in a VB6 program: definitely WON'T work.
I'm trying to search all tables and columns in a database, a la here. The suggested technique is to construct SQL query strings and then EXEC them. This works well, as a stored procedure. (Another example of variable table/column names is here. Again, EXEC is used to execute "dynamic SQL".)
However, my app requires that I do this in a function, not an SP. (Our development framework has trouble obtaining results from an SP.) But in a function, at least on SQL Server 2008 R2, you can't use EXEC; I get this error:
Invalid use of a side-effecting operator 'INSERT EXEC' within a function.
According to the answer to this post, apparently by a Microsoft developer, this is by design; it has nothing to do with the INSERT, only the fact that when you execute dynamically-constructed SQL code, the parser cannot guarantee a lack of side effects. Therefore it won't allow you to create such a function.
So... is there any way to iterate over many tables/columns within a function?
I see from BOL that
The following statements are valid in a function: ...
EXECUTE
statements calling extended stored procedures.
Huh - How could extended SP's be guaranteed side-effect free?
But that doesn't help me anyway:
The extended stored procedure, when it is called from inside a
function, cannot return result sets to the client. Any ODS APIs that
return result sets to the client will return FAIL. The extended stored
procedure could connect back to an instance of SQL Server; however, it
should not try to join the same transaction as the function that
invoked the extended stored procedure.
Since we need the function to return the results of the search, an ESP won't help.
I don't really want to get into extended SP's anyway: incrementing the number of programming languages in the environment would complicate our development environment more than it's worth.
I can think of a few solutions right now, none of which is very satisfactory:
First call an SP that produces the needed data and puts it in a table, then select from the function which merely reads the result from the table; this could be trouble if the search takes a while and two users' searches overlap. Or,
Have the application (not the function) generate a long query naming every table and column name from the db. I wonder if the JDBC driver can handle a query that long. Or,
Have the application (not the function) generate a long series of short queries naming every table and column name from the db. This will make the overall search a lot slower.
Thanks for any suggestions.
P.S. Upon further searching, I stumbled across this question which is closely related. It has no answers.
Update: No longer needed
I think this question is still valid, and we may again have a situation where we need it. However, I don't need an answer anymore for the present problem. After much trial-and-error I managed to get our application framework to retrieve row results from the RDBMS via the JDBC driver from the stored procedure. Therefore getting the thing to work as a function is unnecessary.
But if anyone posts an answer here that helps with the stated problem, I will be happy to upvote and/or accept it as appropriate.
An sp is basically a predefined sql statment with some add ons.
So if you had
PSEUDOCODE
Create SP_DoSomething As
Select * From MyTable
END
And you can't use the SP
Then you just execute the SQL as in "Select * From MyTable"
As for that naff sql code.
For start you could join table to column with a where clause, which would get rid of that line by line if stuff.
Ask another question. Like How could this be improved, there's lots of scope for more attempts than mine.