private Boolean CheckFunctionNeedsColumnDefinitionList()
{
// If and only if a function returns "record" and has no OUT ("o" in proargmodes), INOUT ("b"), or TABLE
// ("t") return arguments to characterize the result columns, we must provide a column definition list.
// See http://pgfoundry.org/forum/forum.php?thread_id=1075&forum_id=519
// We would use our Output and InputOutput parameters to construct that column definition list. If we have
// no such parameters, skip the check: we could only construct "AS ()", which yields a syntax error.
// Updated after 0.99.3 to support the optional existence of a name qualifying schema and allow for case insensitivity
// when the schema or procedure name do not contain a quote.
// The hard-coded schema name 'public' was replaced with code that uses schema as a qualifier, only if it is provided.
String returnRecordQuery;
StringBuilder parameterTypes = new StringBuilder("");
// Process parameters
Boolean seenDef = false;
foreach (NpgsqlParameter p in Parameters)
{
if ((p.Direction == ParameterDirection.Input) || (p.Direction == ParameterDirection.InputOutput))
{
parameterTypes.Append(Connection.Connector.OidToNameMapping[p.TypeInfo.Name].OID.ToString() + " ");
}
if ((p.Direction == ParameterDirection.Output) || (p.Direction == ParameterDirection.InputOutput))
{
seenDef = true;
}
}
if (!seenDef)
{
return false;
}
// Process schema name.
String schemaName = String.Empty;
String procedureName = String.Empty;
String[] fullName = CommandText.Split('.');
String predicate = "prorettype = ( select oid from pg_type where typname = 'record' ) "
+ "and proargtypes=:proargtypes and proname=:proname "
// proargmodes && array['o','b','t']::"char"[] performs just as well, but it requires PostgreSQL 8.2.
+ "and ('o' = any (proargmodes) OR 'b' = any (proargmodes) OR 't' = any (proargmodes)) is not true";
if (fullName.Length == 2)
{
returnRecordQuery =
"select count(*) > 0 from pg_proc p left join pg_namespace n on p.pronamespace = n.oid where " + predicate + " and n.nspname=:nspname";
schemaName = (fullName[0].IndexOf("\"") != -1) ? fullName[0] : fullName[0].ToLower();
procedureName = (fullName[1].IndexOf("\"") != -1) ? fullName[1] : fullName[1].ToLower();
}
else
{
// Instead of defaulting don't use the nspname, as an alternative, query pg_proc and pg_namespace to try and determine the nspname.
//schemaName = "public"; // This was removed after build 0.99.3 because the assumption that a function is in public is often incorrect.
returnRecordQuery =
"select count(*) > 0 from pg_proc p where " + predicate;
procedureName = (CommandText.IndexOf("\"") != -1) ? CommandText : CommandText.ToLower();
}
bool ret;
using (NpgsqlCommand c = new NpgsqlCommand(returnRecordQuery, Connection))
{
c.Parameters.Add(new NpgsqlParameter("proargtypes", NpgsqlDbType.Oidvector));
c.Parameters.Add(new NpgsqlParameter("proname", NpgsqlDbType.Name));
c.Parameters[0].Value = parameterTypes.ToString();
c.Parameters[1].Value = procedureName;
if (schemaName != null && schemaName.Length > 0)
{
c.Parameters.Add(new NpgsqlParameter("nspname", NpgsqlDbType.Name));
c.Parameters[2].Value = schemaName;
}
ret = (Boolean)c.ExecuteScalar();
}
return ret;
}