seitime-frappe/frappe/database/postgres/setup_db.py
hhharsha36 445da4319b
fix: error - permission denied for schema public from Postgres >= 15 during initial DB setup (#23799)
Error from Postgres:
ERROR:  permission denied for schema public at character 14

Error from Frappe:
psql:/home/frappe/frappe-bench/apps/frappe/frappe/database/postgres/framework_postgres.sql:72: ERROR:  permission denied for schema public

Error Causer:
Starting Postgres version >= 15, all users will have the `CREATE` permission revoked by default.

Fix:
Grant relevant privileges to the database in question for the user. In this case, DB owner privilege.

Note: the below two permission attempts were unsuccessful and still caused the same public schema permission error

GRANT USAGE, CREATE ON SCHEMA public TO {frappe.conf.db_name};
GRANT ALL ON SCHEMA public TO {frappe.conf.db_name}

References:
https://stackoverflow.com/questions/74110708/postgres-15-permission-denied-for-schema-public
https://stackoverflow.com/questions/67276391/why-am-i-getting-a-permission-denied-error-for-schema-public-on-pgadmin-4
2023-12-27 16:04:21 +05:30

91 lines
2.9 KiB
Python

import os
import frappe
from frappe.database.db_manager import DbManager
def setup_database():
root_conn = get_root_connection(frappe.flags.root_login, frappe.flags.root_password)
root_conn.commit()
root_conn.sql("end")
root_conn.sql(f"DROP DATABASE IF EXISTS `{frappe.conf.db_name}`")
root_conn.sql(f"DROP USER IF EXISTS {frappe.conf.db_name}")
root_conn.sql(f"CREATE DATABASE `{frappe.conf.db_name}`")
root_conn.sql(f"CREATE user {frappe.conf.db_name} password '{frappe.conf.db_password}'")
root_conn.sql("GRANT ALL PRIVILEGES ON DATABASE `{0}` TO {0}".format(frappe.conf.db_name))
psql_version = root_conn.sql(f"SELECT VERSION()", as_dict=True)
if psql_version and psql_version[0].get("version", "PostgreSQL 14").split()[1] >= "15":
root_conn.sql("ALTER DATABASE `{0}` OWNER TO {0}".format(frappe.conf.db_name))
root_conn.close()
def bootstrap_database(db_name, verbose, source_sql=None):
frappe.connect(db_name=db_name)
import_db_from_sql(source_sql, verbose)
frappe.connect(db_name=db_name)
if "tabDefaultValue" not in frappe.db.get_tables():
import sys
from click import secho
secho(
"Table 'tabDefaultValue' missing in the restored site. "
"This may be due to incorrect permissions or the result of a restore from a bad backup file. "
"Database not installed correctly.",
fg="red",
)
sys.exit(1)
def import_db_from_sql(source_sql=None, verbose=False):
if verbose:
print("Starting database import...")
db_name = frappe.conf.db_name
if not source_sql:
source_sql = os.path.join(os.path.dirname(__file__), "framework_postgres.sql")
DbManager(frappe.local.db).restore_database(
verbose, db_name, source_sql, db_name, frappe.conf.db_password
)
if verbose:
print("Imported from database %s" % source_sql)
def get_root_connection(root_login=None, root_password=None):
if not frappe.local.flags.root_connection:
if not root_login:
root_login = frappe.conf.get("root_login") or None
if not root_login:
root_login = input("Enter postgres super user: ")
if not root_password:
root_password = frappe.conf.get("root_password") or None
if not root_password:
from getpass import getpass
root_password = getpass("Postgres super user password: ")
frappe.local.flags.root_connection = frappe.database.get_db(
host=frappe.conf.db_host,
port=frappe.conf.db_port,
user=root_login,
password=root_password,
)
return frappe.local.flags.root_connection
def drop_user_and_database(db_name, root_login, root_password):
root_conn = get_root_connection(
frappe.flags.root_login or root_login, frappe.flags.root_password or root_password
)
root_conn.commit()
root_conn.sql(
"SELECT pg_terminate_backend (pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = %s",
(db_name,),
)
root_conn.sql("end")
root_conn.sql(f"DROP DATABASE IF EXISTS {db_name}")
root_conn.sql(f"DROP USER IF EXISTS {db_name}")