Access a postgres table using the schema prefix in c# - c#

I'm using postgres in a c# project and i'm trying to make some basic queries such as
qry.CommandText = "select * from LOGIN";
NpgsqlDataReader qryReader = qry.ExecuteReader();
But it says that the table LOGIN does not exist.
I already know that the following query works: qry.CommandText = "select * from \"myDataBase\".LOGIN"; but I would prefer not using it.
I also know from this thread that I can use SET search_path TO myschema,public; to access the table without prefix in psql command line, but I don't see how it would work for my c# projet.
Also, I have another project where I don't need the prefix but I don't know why it works for my other projet and not this one.
Any help would be very appreciated.
Thanks

While SET search_path TO myschema,public; sets the search_path for the current session only, you can make it permanent for the user running the command:
ALTER USER username SET search_path TO myschema, public;

Related

How to Select an out parameter from a MySql Procedure in .net

Assume we have a stored procedure like so
CREATE PROCEDURE CopyValue(IN src INT, OUT dest INT)
BEGIN
SET dest = src;
END
I want to call this from a .net app (assume connection etc created successfully)
var sql = "call CopyValue(100, #destValue); select #destValue as Results;";
The string in the above statement works perfectly well when called in MySql Workbench.
However this - obviously - fails with "MySqlException: Parameter '#destValue' must be defined" when executed on a MySqlCommand object in .net
How do I arrange this statement so I can capture an output parameter from an existing procedure?
NB: I'm running against MySql 5.6, which I can't upgrade at this time.
NB Calling the procedure directly with CommandType.StoredProcedure goes against company guidelines.
By default, user-defined variables aren't allowed in SQL statements by MySQL Connector/NET. You can relax this restriction by adding AllowUserVariables=true; to your connection string. No modifications to your SQL or how you're executing the MySqlCommand should be necessary.
For information about why this is the default, you can read the research on this MySqlConnector issue (which also has the same default behaviour, but a much better error message that will tell you how to solve the problem): https://github.com/mysql-net/MySqlConnector/issues/194
A colleague (who wishes to remain anonymous) has answered this perfectly. Essentially put backticks ` after the # and at the end of the variable name e.g.
#`MyParam`
A fully working example.
static void Main(string[] args)
{
using var con = new MySql.Data.MySqlClient.MySqlConnection("Data Source=localhost; User Id=...;Password=...;Initial Catalog=...");
con.Open();
using var cmd = con.CreateCommand();
cmd.CommandText = "call CopyValue2(100, #`v2`); select #`v2` as Results;";
using var reader = cmd.ExecuteReader();
if (reader.Read())
Console.WriteLine($"Copied Value {reader.GetInt64(0)}");
}
Thanks OG :)

SqlDependency not working with Existing Database

I'm using Signalr with SqlDependency. My code works and it shows me realtime results like I wanted. But the issue is it is working my newly created database. If I change the database to old one the SqlDependency stops work and not getting the change detection on my database table.
Below is my code:
#region SignalRMethods
[System.Web.Script.Services.ScriptMethod()]
[System.Web.Services.WebMethod(EnableSession = true)]
public GlobalApplicationError[] GetErrorsList()
{
var cs = "Data Source=.;Initial Catalog=NotifyDB;Integrated Security=True";
using (var connection = new SqlConnection(cs))
{
connection.Open();
SqlDependency.Start(cs);
using (SqlCommand command = new SqlCommand(#"SELECT [Form_Name],[Message],[Prepared_By_Date] FROM [GlobalApplicationError]", connection))
{
// Make sure the command object does not already have
// a notification object associated with it.
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
using (var reader = command.ExecuteReader())
return reader.Cast<IDataRecord>()
.Select(x => new GlobalApplicationError()
{
Form_Name = x["Form_Name"].ToString(),
Message = x["Message"].ToString(),
Prepared_By_Date = Convert.ToDateTime(x["Prepared_By_Date"])
}).ToList().ToArray();
}
}
}
private static void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
MyHub.Show();
}
#endregion
Above code perfectly works on database NotifyDB but not on my existing one which is eprocure if I change the database in my connection string. As I'm using the asmx web service so I always update the reference of my web service. Plus I've enable_broker set to true on both databases.
Database screen shots:
NotifyDB
eprocure
output
Kindly let me know what I'm doing wrong in my code. Thanks in advance.
Let windup this. After some brainstorming on internet I successfully found my answer.
I've Checked my database sys.transmission_queue using below query:
select * from sys.transmission_queue
As most likely our notification(s) will be there, retained because they cannot be delivered. The transmission_status have an explanation why is this happening.
I found that there is below error:
Error: 15517, State: 1. Cannot execute as the database principal because the principal "dbo" does not exist
Google it and found the below useful link:
Troubleshooting SQL Server Error 15517
after that I run the below query which is briefly defined in above link
EXEC sp_MSForEachDB
'SELECT ''?'' AS ''DBName'', sp.name AS ''dbo_login'', o.name AS ''sysdb_login''
FROM ?.sys.database_principals dp
LEFT JOIN master.sys.server_principals sp
ON dp.sid = sp.sid
LEFT JOIN master.sys.databases d
ON DB_ID(''?'') = d.database_id
LEFT JOIN master.sys.server_principals o
ON d.owner_sid = o.sid
WHERE dp.name = ''dbo'';';
By doing this, I found several databases that sys.databases said had an owner. However, when I checked it from the database's sys.database_principals, the SID didn't match up for dbo. The column I had for dbo_login came back NULL. That was a clear sign of the issue. There is also the possibility you will see a mismatch between dbo_login and sysdb_login. It appears that as long as dbo_login matches a legitimate login, the error is not generated. I found that on some DBs on one of my servers. While it's not causing a problem now, I'll be looking to correct the mismatch.
Correcting the Error:
The easiest way to correct the error is to use ALTER AUTHORIZATION on the databases which have the NULL login match for dbo. It's as simple as:
ALTER AUTHORIZATION ON DATABASE::eprocure TO sa;
So finally. I got what I want and my SQL Dependency is working fine. This is all from my end. Thanks you help me on this post. I appreciate for your precious time. Happy Coding.
Please make sure Query Notifications & Service broker are enabled and permissions for the IIS identify are granted.
Steps to enable : https://techbrij.com/database-change-notifications-asp-net-signalr-sqldependency
To check service broker is enabled execute the below statement
SELECT name, is_broker_enabled FROM sys.databases
To enable service broker
ALTER DATABASE <<DatabaseName>> SET ENABLE_BROKER
To grant permission to a user
GRANT SUBSCRIBE QUERY NOTIFICATIONS TO “<<USERIDENTITY>”

Minimum access levels to run MySql stored procedure

I am trying to setup my .NET 4.7.1 program that is connecting to a MySQL database 8.0 to use the minimum privileges to run.
The .NET program is using MySql.Data to make connection. The minimum right for a user to execute a stored procedure is typically only EXECUTE privilege. This works fine from MySQL workbench or command line.
Upon running the .NET program this does return the following exception:
System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'
To make it easy, I have create a very small demo program to demonstrate the issue.
Setup of the database:
CREATE DATABASE Spike;
CREATE PROCEDURE TestAccess()
BEGIN
END;
CREATE USER Spike#localhost IDENTIFIED WITH mysql_native_password BY 'sample';
GRANT EXECUTE ON PROCEDURE `TestAccess` TO Spike#localhost;
Setup program code:
static void Main(string[] args)
{
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample"))
{
conn.Open();
Console.WriteLine("Connection open");
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
cmd.CommandText = "TestAccess";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
Console.WriteLine("Query executed");
}
Console.ReadKey();
}
The crash happens at the line cmd.ExecuteNonQuery();
The stack from the crash is interesting, since it seems to indicate that the information_schema is queried. When logging all statements I can see that the last statement before the exception is:
SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess'
I cannot grant different rights on information_schema, but I could give more rights on the stored procedure to make more information visible in the routines table, this feels wrong however. Simple tests with granting CREATE and ALTER access also did not work.
Is there something else I can do, without granting too much privileges?
This appears to be a bug in Connector/NET, similar to bug 75301 but a little different. When it's trying to determine parameter metadata for the procedure, it first creates a MySqlSchemaCollection named Procedures with all metadata about the procedure. (This is the SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess' query you see in your log.)
The Spike user account doesn't have permission to read the ROUTINE_DEFINITION column, so it is NULL. Connector/NET expects this field to be non-NULL and throws a SqlNullValueException exception trying to read it.
There are two workarounds:
1) The first, which you've discovered, is to set CheckParameters=False in your connection string. This will disable retrieval of stored procedure metadata (avoiding the crash), but may lead to harder-to-debug problems calling other stored procedures if you don't get the order and type of parameters exactly right. (Connector/NET can no longer map them for you using the metadata.)
2) Switch to a different ADO.NET MySQL library that doesn't have this bug: MySqlConnector on NuGet. It's highly compatible with Connector/NET, performs faster, and fixes a lot of known issues.
I found an answer with which I am quite pleased. It is changing the connection string by adding CheckParameters=false:
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample;CheckParameters=false"))
This disables parameter checking, and thereby information_schema queries.

MySQL Change "user" table entry via WinForms C#

Quick question - is it possible to change the password of a user that has been entered into the "user" table under the MySQL database via a WinForm app?
I've been inserting and selecting data from a database I created, but if I ever wanted to change the MySQL password, I was wondering if this is possible via C#. Reason I say this is because ATM the connectionstring is hard-coded to take the username and password (maybe someone can give advice on how not to store the password in the connection string in App.config too).
Thanks :)
Take something like this post and change the statement in the command string to use an ALTER USER instead:
using(MySqlConnection Connection = new MySqlConnection("SERVER=localhost;UID=root;"))
using(MySqlCommand Command = new MySqlCommand("ALTER USER 'username'#'localhost' IDENTIFIED BY 'password';", Connection))
{
Connection.Open();
Command.ExecuteNonQuery();
}

MySql.Data.MySqlClient Error when calling stored procedure

I am running into an issue, that I believe lies within my privileges granted. However, I can't figure out why this is happening. I have a stored procedure in MySQL defined by:
DELIMITER //
CREATE PROCEDURE my_stored_procedure (var_one VARCHAR(20), var_two INT4)
BEGIN
UPDATE table_name SET ACTIVATION_DATE = UTC_TIMESTAMP(),
DEACTIVATION_DATE = TIMESTAMPADD(MONTH, var_two, UTC_TIMESTAMP()),
USER_ACTIVATED = 1 WHERE ID = var_one;
END //
DELIMITER ;
I am calling this from my c# application. The code runs fine when I use userA's credentials. However, when I use userB it doesn't work. userA was granted privileges with the command:
GRANT ALL PRIVILEGES ON * . * TO 'userA'#'%';
userB was granted privileges with these commands:
GRANT UPDATE, SELECT ON current_db.table_im_updating TO 'userB'#'%';
GRANT EXECUTE ON PROCEDURE my_stored_procedure TO 'userB'#'%';
My code to call the mysql stored procedure is as follows:
connection = new MySql.Data.MySqlClient.MySqlConnection("server=ip_address; port=3306; database=data_base; UID=userA; password=password; pooling=false");
MySql.Data.MySqlClient.MySqlCommand command = new MySql.Data.MySqlClient.MySqlCommand();
command.Connection = connection;
command.CommandText = "my_stored_procedure";
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.AddWithValue("#_id","associated_id");
command.Parameters["#_id"].Direction = System.Data.ParameterDirection.Input;
command.Parameters.AddWithValue("#subscription_length", "6");
command.Parameters["#subscription_length"].Direction = System.Data.ParameterDirection.Input;
command.ExecuteNonQuery();
Like I mentioned. This code works fine when userA and userA's password are entered; but when I switch to userB the error says,
System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'
It is also worth noting that if I change my method of calling the procedure to this:
MySql.Data.MySqlClient.MySqlCommand command = new MySql.Data.MySqlClient.MySqlCommand("CALL my_stored_procedure(var_one, var_two)", connection);
I get no errors. I am not trying to just make my code work, I want it to work properly. Please help me understand what is causing this Error. Thanks.
TL;DR
userB should be granted with SELECT access to the mysql.proc table.
Explaination
First, MySQL Connnector/NET is executed SHOW CREATE PROCEDURE my_stored_procedure to get all parameters definition. (Order, Direction, DbType etc.)
Then, it will combine procedure name and parameters to create a sql like CALL my_stored_procedure(var_one, var_two) to execute.
To use SHOW CREATE PROCEDURE, you must be the user named in the routine DEFINER clause or have SELECT access to the mysql.proc table. If you do not have privileges for the routine itself, the value displayed for the Create Procedure field will be NULL.
-- Doc: SHOW CREATE PROCEDURE Syntax
-- Issue: Connector 8.0 - Stored Procedure Error in MySqlDataReader
Give the userB the privileges to Execute the SP and add CheckParameters=false to Connection String

Categories