Postgres driver doesn't find table in go - database

Really strange yet very common error. Relation "users" does not exist. I know what you are saying - that's been asked before! And it has, but work with me because I'm doing a bunch of checks and it still doesn't go through.
First, this is the migration:
CREATE TABLE users (
id serial PRIMARY KEY,
obfuscated_id VARCHAR(128) NOT NULL UNIQUE,
email VARCHAR(128) NOT NULL UNIQUE,
encrypted_password VARCHAR(128) NOT NULL,
created_at TIMESTAMP,
updated_at TIMESTAMP,
active BOOLEAN DEFAULT TRUE
);
And this is the command I'm using to run that migration:
migrate -path ./migrations -database postgres://myname:password#localhost:5432/five_three_one_development?sslmode=disable up
I've manually tested that the db exists:
psql
\c five_three_one_development
\dt
Schema | Name | Type | Owner
--------+-------------------+-------+----------
public | schema_migrations | table | myname
public | users | table | myname
I've manually altered the password on the table using /password and set it to password.
Here are the environment variables:
DB_NAME=five_three_one_development
DB_PASS=password
DB_USER=myname
And when I log those variables I get the same values back:
fmt.Printf("NAME:" + os.Getenv("DB_NAME"))
fmt.Printf("USER:" + os.Getenv("DB_USER"))
fmt.Printf("DB_PASS:" + os.Getenv("DB_PASS"))
I also perform an environment test at the top of my development server to check that the db is reachable.
func (c *ApplicationContext) PerformEnvChecks() {
err := c.Database.Ping()
if err != nil {
log.Fatalf("Database environment check failed: %s", err)
}
r, err := c.Database.Exec("SELECT * FROM users")
if err != nil {
log.Fatal(err) // --> pq: relation "users" does not exist
}
fmt.Printf("Tables: %v", r)
}
And then it fails on the c.Database.Exec("SELECT * FROM users") line which means that it's connected to the right database but it cannot find the table.
Out of ideas on this one - thoughts?
Edit
Feature request idea for postgresql folks: \connection_string -> returns the postgresql connection string given the current user inside of the database connected to.

Golang sql driver isn't clear about the order it expects. Ditch it. Save the whole connection string into a DATABASE URL variable and use that. Annoying but it seems to have solved the problem.
Pass this as a connection string: postgres://myname:password#localhost:5432/five_three_one_development?sslmode=disable and forget trying to build it up.

Related

MS-SQL server throws error when two foreign keys are set on same table using GORM

I am doing database migrations using GORM. So I define structs and run them through GORM's AutoMigrate function.
type Person struct {
ID string `gorm:"type:varchar(36);primary_key"`
}
err := db.Table("persons").AutoMigrate(&Person{}).Error
type Address struct {
ID string `gorm:"type:varchar(36);primary_key"`
PersonID string `gorm:"column:person_id;type:varchar(36);NOT NULL"`
}
err = db.AutoMigrate(&Address{}).Error
err = db.Model(&Address{}).AddForeignKey("person_id", "persons(id)", "NO ACTION", "CASCADE").Error
type Contact struct {
ID string `gorm:"type:varchar(36);primary_key"`
AddressID null.String `gorm:"column:address_id;type:varchar(36);NOT NULL"`
PersonID string `gorm:"column:person_id;type:varchar(36);NOT NULL"`
}
err = db.AutoMigrate(&Contact{}).Error
err = db.Model(&Contact{}).AddForeignKey("address_id", "addresses(id)", "NO ACTION", "CASCADE").Error
err = db.Model(&Contact{}).AddForeignKey("person_id", "persons(id)", "NO ACTION", "CASCADE").Error
In the above code, which ever is the second call to the AddForeignKey function on Contacts table is giving error :
mssql: Could not create constraint or index. See previous errors.
Even if I move person_id foreign key above address_id foreign key, then address_id foreign key fails.
I am running MS-SQL server using latest docker container setup(microsoft/mssql-server-linux:latest). Is this something regarding naming of constraint. If yes, then how can we set using GORM? Everything works fine with My-SQL.
It would be really helpful if I get a solution. I cannot run raw queries. Migrations have to be done using GORM only.
Thank You
Multiple foreignkeys can't have 'no action', 'cascade' on the same table. If u use no action, no action u can but u have to handle deletion and updating your self. What I usually do is turn on logmode and copy paste the log sql statement into SQL. This will give u a more clear error.

Why does FireDAC ignore index name?

I'm trying to creating a table in a SQL Server database using FireDAC. However, instead of using the index name I provide, FireDAC uses a bad index name, raising an exception and the table does not get created. Am I doing something wrong? If not, is there a work-around?
Note that I'm using the valid database schema name cnf for TableName. I specifically need to create the table in a schema.
Simplest test case:
var
Connection: TFDConnection;
Table: TFDTable;
begin
Connection := TFDConnection.Create(nil);
Table := TFDTable.Create(nil);
try
Connection.Params.Add ('DriverID=MSSQL');
Connection.Params.Add ('OSAuthent=No');
Connection.Params.Add ('User_Name=sa');
Connection.Params.Add ('Password=XXXXXX');
Connection.Params.Add ('Server=DAVE-DELL\MSSQLSERVER2016');
Connection.Params.Add ('Database=PROJECT_DB');
Connection.Params.Add ('MARS=No');
Connection.Open;
Table.Connection := Connection;
Table.TableName := 'cnf.TestTable';
Table.FieldDefs.Add ('TableID', ftAutoInc, 0, true);
Table.FieldDefs.Add ('Field1', ftInteger, 0, true);
Table.FieldDefs.Add ('Field2', ftstring, 100, true);
Table.IndexDefs.Add ('PK_XYZ', 'TableID', [ixPrimary]); // should use this index name!
Table.CreateTable (true);
finally
Table.Free;
Connection.Free;
end;
end;
An exception is raised:
[FireDAC][Phys][ODBC][Microsoft][SQL Server Native Client 11.0][SQL Server]Incorrect syntax near '.'.
Running SQL Server Profiler shows me that FireDAC is trying to create the index using the following SQL code:
ALTER TABLE temp.TestTable ADD CONSTRAINT [cnf].[PK_TestTable] PRIMARY KEY (TableID)
And, of course, [cnf].[PK_TestTable] is not a valid index name in T-SQL, which is the crux of the problem.
If I remove the line Table.IndexDefs.Add, the table is created properly, but without the index.
If I replace that line with the following, it gives the same problem:
with Table.IndexDefs.AddIndexDef do begin
Name := 'PK_XYZ';
Options := [ixPrimary];
Fields := 'TableID';
end;
If I replace setting the table name with the following, it gives the same problem:
Table.TableName := 'TestTable';
Table.SchemaName := 'cnf';
Why is it using it's own (wrong) index name, instead of the name I gave it? (i.e. PK_XYZ)
Embarcadero® Delphi 10.1 Berlin Version 24.0.25048.9432
SQL Server 2016 (SP2-CU4) - 13.0.5233.0 (X64)
Am I doing something wrong?
Why is it using it's own (wrong) index name, instead of the name I gave it?
You seem to be doing everything just right. The issue is with the generated SQL command as you have tracked that down. SQL Server doesn't allow schema name in constraint name when adding a constraint using ALTER TABLE. Constraints created this way automatically become part of schema of the related table, however you should later use schema name when referring to the constraint:
SELECT OBJECT_ID('cnf.PK_XYZ')
Now where do the things go wrong? FireDAC uses TFDPhysCommandGenerator and its ancestors to generate SQL commands for specific DBMS. Your call to CreateTable method results in call to TFDPhysCommandGenerator.GetCreatePrimaryKey, which is responsible for generating SQL for primary key. It also contains this code:
sTab := GetFrom;
FConnMeta.DecodeObjName(sTab, rName, nil, [doUnquote]);
rName.FObject := 'PK_' + rName.FObject;
Result := 'ALTER TABLE ' + sTab + ' ADD CONSTRAINT ' +
FConnMeta.EncodeObjName(rName, nil, [eoQuote, eoNormalize]) + ' PRIMARY KEY (';
What this code does is that it takes your fully qualified table name (sTab) splits it (DecodeObjName) into parts (rName) prepends 'PK_' to table name and joins the parts (EncodeObjName) back to fully qualified name, which is then used as the constraint name for your primary key. Now we can clearly see that command generator ignores your index name and generates erroneous T-SQL. This can either be a bug or just a not supported feature. EMBT has to make decision on that. I'd recommend reporting it as a bug.
Is there a work-around?
Yes, you can either hook problematic method or you can override it in your own derived class. Implementation none of these is trivial and due to legal issues I'm not going to extend it here, because I would have to duplicate the original FireDAC code.
As for the syntax error adding these lines to 'TFDPhysCommandGenerator.GetCreatePrimaryKey' implementation after DecodeObjName would fix the issue:
rName.FCatalog := '';
rName.FSchema := '';
rName.FBaseObject := '';
rName.FLink := '';
Fixing constraint name is going to be more cumbersome than that, because the method only receives index column names as argument and has no obvious access to original IndexDefs where you could just use index name as primary key constraint name. Gaining access to index name from there would also allow you to get rid of decoding/encoding table name into index name. This process, however, could be essential for other DMBS's than SQL Server.
PS: If only half of all the questions were written in this manner ... Thank you for this wonderful question.

obtain the real identity of the connected user

dxStatusbar1.Panels1.Text :=
DataModule2.UniConnectDialog1.Connection.Username;
...gives me the username that has connected to sql server.
However the connected user has a different name in the actual database.
Example:
His login name for the sql server is 'John' and is user mapped to 'Northwind' database.
However in 'Northwind' database he is called 'John Smith'.
And this is the name (John Smith) I am trying to have displayed in dxStatusbar1.Panels1.Text
after he connects.
How can I get that ?
edit :
Tried Victoria suggestion :
UserName := DataModule2.UniConnection1.ExecSQL('SELECT :Result = CURRENT_USER', ['Result']);
dxStatusbar1.Panels[1].Text := UserName;
but get :
I couldn't find any UniDAC API way to get currently connected user name (not even for SDAC), so I would just issue a SQL command querying CURRENT_USER and grab the name from the result:
SELECT CURRENT_USER;
Or in the Unified SQL way with the USER function:
SELECT {fn USER};
Since you've mentioned stored procedure in your comment, it sounds to me like you probably want to get this information directly from a connection object without using query object. If that is so, you don't even need to have a stored procedure but execute directly command like this:
var
UserName: string;
begin
UserName := UniConnection1.ExecSQL('SELECT :Result = CURRENT_USER', ['Result']);
...
end;
Or in unified way:
var
UserName: string;
begin
UserName := UniConnection1.ExecSQL('SELECT :Result = {fn USER}', ['Result']);
...
end;
One of these might do the job for you. Haven't tested.
SELECT ORIGINAL_LOGIN()
SELECT SYSTEM_USER
SELECT SUSER_SNAME()
Hope it helps.
ORIGINAL_LOGIN: Returns the name of the login that connected to the instance of SQL Server. You can use this function to return the identity of the original login in sessions in which there are many explicit or implicit context switches.
SYSTEM_USER: Allows a system-supplied value for the current login to be inserted into a table when no default value is specified.
SUSER_SNAME: Returns the login name associated with a security identification number (SID).

How to make the 'public' schema default in a Scala Play project that uses PostgreSQL?

I am not sure if my issue connecting to the Scala Play 2.5.x Framework or to PostgreSQL so I am going to describe my setup.
I am using the Play 2.5.6 with Scala and PostgreSQL 9.5.4-2 from the BigSQL Sandboxes. I use the Play Framework default evolution package to manage the DB versions.
I created a new database in BigSQL Sandbox's PGSQL and PGSQL created a default schema called public. I use this schema for development.
I would like to create a table with the following script (1.sql in DB evolution config):
# Initialize the database
# --- !Ups
CREATE TABLE user (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
creation_date TIMESTAMP NOT NULL
);
# --- !Downs
DROP TABLE user;
Besides that I would like to read the table with a code like this:
val resultSet = statement.executeQuery("SELECT id, name, email FROM public.user WHERE id=" + id.toString)
I got an error if I would like to execute any of the mentioned code or even if I use the CREATE TABLE... code in pgadmin. The issue is with the user table name. If I prefix it with public (i.e. public.user) everything works fine.
My questions are:
Is it normal to prefix the table name with the schema name every time? It seems to odd to me.
How can I make the public schema a default option so I do not have to qualify the table name? (e.g. CREATE TABLE user (...); will not throw an error)
I tried the following:
I set the search_path for my user: ALTER USER my_user SET search_path to public;
I set the search_path for my database: ALTER database "my_database" SET search_path TO my_schema;
search_path correctly shows this: "$user",public
I got the following errors:
In Play: p.a.d.e.DefaultEvolutionsApi - ERROR: syntax error at or near "user"
In pgadmin:
ERROR: syntax error at or near "user"
LINE 1: CREATE TABLE user (
********** Error **********
ERROR: syntax error at or near "user"
SQL state: 42601
Character: 14
This has nothing to do with the default schema. user is a reserved word.
You need to use double quotes to be able to create such a table:
CREATE TABLE "user" (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
creation_date TIMESTAMP NOT NULL
);
But I strongly recommend not doing that. Find a different name that does not require a quoted identifier.

postgresql won't accept a specific key

So I'm using postgresql 9.5 to store a bunch of data in a table named ids. The data is stored like this :
id1 (UNIQUE, NOT NULL) | bool1 | bool2 | bool3 | id2 (not unique)
id1 and id2 are text variables.
When I try to insert new data into the database I use this query :
"INSERT INTO ids (id1, bool2, id2) VALUES (%s, TRUE, %s) ON CONFLICT (id1) DO UPDATE SET interaction = TRUE, id2 = %s;"
Now when I try to insert this specific id1 : c1316a6a-3bdd-4aeb-a1b6-b3044851880a__19
that is unique (I double checked that) the database hangs. While I am using python and psycopg2 to call the query, if I try to insert that key into the database by hand (by connecting to the database via CLI or GUI) the database still hangs.
However, if I create a similar database and use the exact same command, it works fine.
Any ideas as to why it hangs and how to fix it ?
EDIT :
Thank you, a_horse_with_no_name
It was indeed a waiting transaction. I killed its pid and everything worked fine afterwards.
Thanks again

Resources