Functions should be scoped appropriately so that they only deal with one thing at a time. A function that checks for network connectivity isn't going to be checking for missing rows. Those are different problems, and should be handled by different functions.
Using your example, we have a function that queries a database. It will be given a valid database connection, and return the result of the query.
There is no "valid database connection" logic, since that is handled elsewhere. There is no result validation logic, since that is handled upstream. This function only cares about A) querying and B) returning a value (possibly null). The only exceptions that is handles is when something specific to it's domain goes wrong - for example, unauthorized access to a table. That is an error that is above networking (the connection worked fine) but clearly not a data validation problem (no data), so we handle the exception here.
If you find yourself throwing exceptions "across problem domains", that's a good indicator that your functions are doing too much.
You can't just assume that a valid database connection will remain valid the entire time you're using it. The network or server is free to go down at any time. In practice, this rarely happens, it's an exceptional condition. Exceptions are the best way to model these kind of errors.
Sure, but the query goes through the layer of functions that actually deals with the database connection. If an error occurs, that layer is responsible and the "higher" layers simply pass on the exception that is thrown.
Point is: the function that deals with database response should never be responsible for dealing with database connection errors.
Using your example, we have a function that queries a database. It will be given a valid database connection, and return the result of the query.
There is no "valid database connection" logic, since that is handled elsewhere. There is no result validation logic, since that is handled upstream. This function only cares about A) querying and B) returning a value (possibly null). The only exceptions that is handles is when something specific to it's domain goes wrong - for example, unauthorized access to a table. That is an error that is above networking (the connection worked fine) but clearly not a data validation problem (no data), so we handle the exception here.
If you find yourself throwing exceptions "across problem domains", that's a good indicator that your functions are doing too much.