Skip to content

Commit

Permalink
Merge pull request #3917 from mathesar-foundation/fast_install
Browse files Browse the repository at this point in the history
Fast install
  • Loading branch information
pavish authored Oct 4, 2024
2 parents be8bc92 + d1c75a5 commit fd47b3f
Show file tree
Hide file tree
Showing 10 changed files with 4,666 additions and 145 deletions.
6 changes: 3 additions & 3 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import random
import string
import os
import psycopg

# These imports come from the mathesar namespace, because our DB setup logic depends on it.
from django.db import connection as dj_connection
Expand All @@ -11,7 +12,6 @@
from sqlalchemy_utils import database_exists, create_database, drop_database

from db.engine import add_custom_types_to_ischema_names, create_engine as sa_create_engine
from db.types import install
from db.sql import install as sql_install
from db.schemas.operations.drop import drop_schema_via_name as drop_sa_schema
from db.schemas.operations.create import create_schema_if_not_exists_via_sql_alchemy
Expand Down Expand Up @@ -74,8 +74,8 @@ def __create_db(db_name):
create_database(engine.url)
created_dbs.add(db_name)
# Our default testing database has our types and functions preinstalled.
install.install_mathesar_on_database(engine)
sql_install.install(engine)
with psycopg.connect(str(engine.url)) as conn:
sql_install.install(conn)
engine.dispose()
return db_name
yield __create_db
Expand Down
12 changes: 5 additions & 7 deletions db/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def execute_msar_func_with_engine(engine, func_name, *args):
with psycopg.connect(conn_str) as conn:
# Returns a cursor
return conn.execute(
f"SELECT msar.{func_name}({','.join(['%s']*len(args))})",
f"SELECT msar.{func_name}({','.join(['%s'] * len(args))})",
args
)

Expand Down Expand Up @@ -52,7 +52,7 @@ def exec_msar_func(conn, func_name, *args):
"""
# Returns a cursor
return conn.execute(
f"SELECT msar.{func_name}({','.join(['%s']*len(args))})", args
f"SELECT msar.{func_name}({','.join(['%s'] * len(args))})", args
)


Expand All @@ -66,14 +66,12 @@ def select_from_msar_func(conn, func_name, *args):
*args: The list of parameters to pass
"""
cursor = conn.execute(
f"SELECT * FROM msar.{func_name}({','.join(['%s']*len(args))})", args
f"SELECT * FROM msar.{func_name}({','.join(['%s'] * len(args))})", args
)
cursor.row_factory = dict_row
return cursor.fetchall()


def load_file_with_engine(engine, file_handle):
def load_file_with_conn(conn, file_handle):
"""Run an SQL script from a file, using psycopg."""
conn_str = str(engine.url)
with psycopg.connect(conn_str) as conn:
conn.execute(file_handle.read())
conn.execute(file_handle.read())
64 changes: 37 additions & 27 deletions db/install.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from psycopg.errors import InsufficientPrivilege
from sqlalchemy import text
from sqlalchemy.exc import OperationalError, ProgrammingError
import psycopg
from psycopg.errors import OperationalError, InsufficientPrivilege
from psycopg import sql

from db import engine
from db.sql import install as sql_install
from db.types import install as types_install


def install_mathesar(
Expand All @@ -18,19 +16,22 @@ def install_mathesar(
root_db='postgres'
):
"""Create database and install Mathesar on it."""
user_db_engine = engine.create_future_engine(
username, password, hostname, database_name, port,
connect_args={"connect_timeout": 10}
)

try:
user_db_engine.connect()
conn = psycopg.connect(
host=hostname,
port=port,
dbname=database_name,
user=username,
password=password,
)
print(
"Installing Mathesar on preexisting PostgreSQL database"
f" {database_name} at host {hostname}..."
)
types_install.install_mathesar_on_database(user_db_engine)
sql_install.install(user_db_engine)
user_db_engine.dispose()
with conn:
sql_install.install(conn)

except OperationalError as e:
if create_db:
database_created = _create_database(
Expand All @@ -45,13 +46,19 @@ def install_mathesar(
else:
database_created = False
if database_created:
conn = psycopg.connect(
host=hostname,
port=port,
dbname=database_name,
user=username,
password=password,
)
print(
"Installing Mathesar on PostgreSQL database"
f" {database_name} at host {hostname}..."
)
types_install.install_mathesar_on_database(user_db_engine)
sql_install.install(user_db_engine)
user_db_engine.dispose()
with conn:
sql_install.install(conn)
else:
print(f"Skipping installing on DB with key {database_name}.")
raise e
Expand All @@ -71,21 +78,24 @@ def _create_database(
# Database. So we use the default database `postgres` that comes with
# postgres.
# TODO Throw correct error when the root database does not exist.
root_db_engine = engine.create_future_engine(
username, password, hostname, root_database, port,
connect_args={"connect_timeout": 10}
root_db_conn = psycopg.connect(
host=hostname,
port=port,
dbname=root_database,
user=username,
password=password,
)
try:
with root_db_engine.connect() as conn:
conn.execution_options(isolation_level="AUTOCOMMIT")
conn.execute(text(f'CREATE DATABASE "{db_name}"'))
root_db_engine.dispose()
with root_db_conn as conn:
cursor = conn.cursor()
conn.autocommit = True
cursor.execute(sql.SQL(f'CREATE DATABASE "{db_name}"'))
cursor.close()
print(f"Created DB is {db_name}.")
return True
except ProgrammingError as e:
if isinstance(e.orig, InsufficientPrivilege):
print(f"Database {db_name} could not be created due to Insufficient Privilege")
return False
except InsufficientPrivilege:
print(f"Database {db_name} could not be created due to Insufficient Privilege")
return False
except Exception:
print(f"Database {db_name} could not be created!")
return False
Expand Down
37 changes: 0 additions & 37 deletions db/sql/00_msar.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5157,40 +5157,3 @@ BEGIN
);
END;
$$ LANGUAGE plpgsql RETURNS NULL ON NULL INPUT;


----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
-- FUNCTIONS/COMMANDS RELATED TO GRANTING APPROPRIATE PERMISSIONS FOR msar, __msar AND mathesar_types
-- SCHEMAS TO PUBLIC.
--
-- !!! DO NOT ADD ANY FUNCTIONS PAST THIS POINT !!!
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------

CREATE OR REPLACE FUNCTION
msar.grant_usage_on_custom_mathesar_types_to_public() RETURNS void AS $$
BEGIN
EXECUTE string_agg(
format(
'GRANT USAGE ON TYPE %1$I.%2$I TO PUBLIC',
pgn.nspname,
pgt.typname
),
E';\n'
) || E';\n'
FROM pg_catalog.pg_type AS pgt
JOIN pg_catalog.pg_namespace pgn ON pgn.oid = pgt.typnamespace
WHERE (pgn.nspname = 'msar'
OR pgn.nspname = '__msar'
OR pgn.nspname = 'mathesar_types')
AND (pgt.typtype = 'c' OR pgt.typtype = 'd')
AND pgt.typcategory != 'A';
END;
$$ LANGUAGE plpgsql;


GRANT USAGE ON SCHEMA __msar, msar, mathesar_types TO PUBLIC;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA msar, __msar, mathesar_types TO PUBLIC;
GRANT SELECT ON ALL TABLES IN SCHEMA msar, __msar, mathesar_types TO PUBLIC;
SELECT msar.grant_usage_on_custom_mathesar_types_to_public();
Loading

0 comments on commit fd47b3f

Please sign in to comment.