├── .flake8 ├── .github └── workflows │ ├── publish.yml │ └── test.yml ├── .gitignore ├── CHANGELOG.rst ├── DEVELOPMENT.rst ├── LICENSE ├── MANIFEST.in ├── README.rst ├── check.sh ├── mbdata ├── __init__.py ├── api │ ├── __init__.py │ ├── commonsettings.py │ ├── data.py │ ├── errors.py │ ├── includes.py │ └── serialize.py ├── config.py ├── data │ ├── __init__.py │ ├── artist.py │ ├── label.py │ ├── recording.py │ └── release_group.py ├── models.py ├── sample_data.py ├── search.py ├── sql │ ├── CalculateRelatedTags.sql │ ├── CreateCollateIndexes.sql │ ├── CreateCollations.sql │ ├── CreateConstraints.sql │ ├── CreateFKConstraints.sql │ ├── CreateFunctions.sql │ ├── CreateIndexes.sql │ ├── CreateMirrorIndexes.sql │ ├── CreateMirrorOnlyFunctions.sql │ ├── CreateMirrorOnlyTriggers.sql │ ├── CreatePrimaryKeys.sql │ ├── CreateReplicationTriggers.sql │ ├── CreateReplicationTriggers2.sql │ ├── CreateSearchConfiguration.sql │ ├── CreateSearchIndexes.sql │ ├── CreateTables.sql │ ├── CreateTriggers.sql │ ├── CreateTypes.sql │ ├── CreateViews.sql │ ├── DisableLastUpdatedTriggers.sql │ ├── DropAll.sql │ ├── DropCollateIndexes.sql │ ├── DropCollations.sql │ ├── DropFKConstraints.sql │ ├── DropFunctions.sql │ ├── DropIndexes.sql │ ├── DropMirrorOnlyFunctions.sql │ ├── DropMirrorOnlyTriggers.sql │ ├── DropPrimaryKeys.sql │ ├── DropReplicationTriggers.sql │ ├── DropReplicationTriggers2.sql │ ├── DropSearchIndexes.sql │ ├── DropTables.sql │ ├── DropTriggers.sql │ ├── DropTypes.sql │ ├── DropViews.sql │ ├── EnableLastUpdatedTriggers.sql │ ├── Extensions.sql │ ├── InsertDefaultRows.sql │ ├── InsertTestData.sql │ ├── ReplicationSetup.sql │ ├── SetSequences.sql │ ├── TruncateTables.sql │ ├── caa │ │ ├── CreateEditFKConstraints.sql │ │ ├── CreateFKConstraints.sql │ │ ├── CreateFunctions.sql │ │ ├── CreateIndexes.sql │ │ ├── CreatePrimaryKeys.sql │ │ ├── CreateReplicationTriggers.sql │ │ ├── CreateReplicationTriggers2.sql │ │ ├── CreateTables.sql │ │ ├── CreateTriggers.sql │ │ ├── CreateViews.sql │ │ ├── DropFKConstraints.sql │ │ ├── DropFunctions.sql │ │ ├── DropIndexes.sql │ │ ├── DropPrimaryKeys.sql │ │ ├── DropReplicationTriggers.sql │ │ ├── DropReplicationTriggers2.sql │ │ ├── DropTables.sql │ │ ├── DropTriggers.sql │ │ ├── DropViews.sql │ │ ├── SetSequences.sql │ │ └── TruncateTables.sql │ ├── dbmirror2 │ │ ├── MasterSetup.sql │ │ ├── README │ │ ├── RefreshColumnInfo.sql │ │ └── ReplicationSetup.sql │ ├── documentation │ │ ├── CreateFKConstraints.sql │ │ ├── CreatePrimaryKeys.sql │ │ ├── CreateReplicationTriggers.sql │ │ ├── CreateReplicationTriggers2.sql │ │ ├── CreateTables.sql │ │ ├── DropFKConstraints.sql │ │ ├── DropFunctions.sql │ │ ├── DropIndexes.sql │ │ ├── DropPrimaryKeys.sql │ │ ├── DropReplicationTriggers.sql │ │ ├── DropReplicationTriggers2.sql │ │ ├── DropSearchIndexes.sql │ │ ├── DropTables.sql │ │ ├── DropTriggers.sql │ │ ├── DropViews.sql │ │ ├── SetSequences.sql │ │ └── TruncateTables.sql │ ├── eaa │ │ ├── CreateEditFKConstraints.sql │ │ ├── CreateFKConstraints.sql │ │ ├── CreateFunctions.sql │ │ ├── CreateIndexes.sql │ │ ├── CreatePrimaryKeys.sql │ │ ├── CreateReplicationTriggers.sql │ │ ├── CreateReplicationTriggers2.sql │ │ ├── CreateTables.sql │ │ ├── CreateTriggers.sql │ │ ├── CreateViews.sql │ │ ├── DropFKConstraints.sql │ │ ├── DropFunctions.sql │ │ ├── DropIndexes.sql │ │ ├── DropPrimaryKeys.sql │ │ ├── DropReplicationTriggers.sql │ │ ├── DropReplicationTriggers2.sql │ │ ├── DropTables.sql │ │ ├── DropTriggers.sql │ │ ├── DropViews.sql │ │ ├── SetSequences.sql │ │ └── TruncateTables.sql │ ├── json_dump │ │ ├── CreateIndexes.sql │ │ ├── CreatePrimaryKeys.sql │ │ ├── CreateTables.sql │ │ ├── DropFKConstraints.sql │ │ ├── DropIndexes.sql │ │ ├── DropPrimaryKeys.sql │ │ ├── DropTables.sql │ │ └── TruncateTables.sql │ ├── report │ │ ├── CreateTables.sql │ │ └── TruncateTables.sql │ ├── sitemaps │ │ ├── CreateFKConstraints.sql │ │ ├── CreateIndexes.sql │ │ ├── CreateTables.sql │ │ ├── DropFKConstraints.sql │ │ ├── DropIndexes.sql │ │ ├── DropTables.sql │ │ └── TruncateTables.sql │ ├── statistics │ │ ├── CreateIndexes.sql │ │ ├── CreatePrimaryKeys.sql │ │ ├── CreateReplicationTriggers.sql │ │ ├── CreateReplicationTriggers2.sql │ │ ├── CreateTables.sql │ │ ├── DropIndexes.sql │ │ ├── DropPrimaryKeys.sql │ │ ├── DropReplicationTriggers.sql │ │ ├── DropReplicationTriggers2.sql │ │ ├── DropTables.sql │ │ ├── SetSequences.sql │ │ └── TruncateTables.sql │ └── wikidocs │ │ ├── CreatePrimaryKeys.sql │ │ ├── CreateReplicationTriggers.sql │ │ ├── CreateReplicationTriggers2.sql │ │ ├── CreateTables.sql │ │ ├── DropPrimaryKeys.sql │ │ ├── DropReplicationTriggers.sql │ │ ├── DropReplicationTriggers2.sql │ │ ├── DropTables.sql │ │ └── TruncateTables.sql ├── tests │ ├── __init__.py │ ├── test_tools_genmodels.py │ └── test_utils_sql.py ├── tools │ ├── __init__.py │ ├── dump_sample_data.py │ └── genmodels.py ├── types.py └── utils │ ├── __init__.py │ ├── models.py │ └── sql.py ├── poetry.lock ├── pyproject.toml ├── scripts ├── create_sample_db.py ├── create_solr_home.py ├── dump_sample_data.sh ├── export_solr_triggers.py ├── update_models.sh ├── update_sql.sh └── upload_to_pypi.sh └── settings.py.sample /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = F401,E501,W391,F405,E128,W291,E126,E121,F403 3 | per-file-ignores = 4 | mbdata/sample_data.py:E501 5 | mbdata/models.py:E501 6 | mbdata/api/tests/__init__.py:E402 7 | max-line-length = 160 8 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Delivery 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | environment: 11 | name: pypi 12 | url: https://pypi.org/p/mbdata 13 | permissions: 14 | id-token: write 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: actions/setup-python@v5 18 | with: 19 | python-version: '3.12' 20 | - uses: snok/install-poetry@v1 21 | with: 22 | plugins: | 23 | poetry-dynamic-versioning[plugin] 24 | - run: poetry build 25 | - uses: pypa/gh-action-pypi-publish@release/v1 26 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | python_version: [ '3.9', '3.10', '3.11', '3.12', '3.13' ] 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Install Python 17 | uses: actions/setup-python@v5 18 | with: 19 | python-version: ${{ matrix.python_version }} 20 | - name: Install Poetry 21 | uses: snok/install-poetry@v1 22 | - name: Install application dependencies 23 | run: poetry install 24 | - name: Run tests 25 | run: ./check.sh 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | *.db 4 | /e/ 5 | /.tox/ 6 | /.mypy_cache/ 7 | /dist/ 8 | mbdata.egg-info/ 9 | settings.py 10 | venv/ 11 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Version 30.0.0 2 | ============== 3 | 4 | - Schema change 30. 5 | - Allow selecting MBS tag or branch from which to update SQL 6 | - Delete useless /updates SQL folder after update 7 | - Drop support for Python 3.8, add support for 3.13 8 | - Move the repository maintenance under MetaBrainz umbrella 9 | 10 | Version 29.0.0 11 | ============== 12 | 13 | - Schema change 29. 14 | 15 | Version 27.1.0 16 | ============== 17 | 18 | - Added `mbslave init` command. 19 | 20 | Version 27.0.0 21 | ============== 22 | 23 | - Schema change 27. 24 | 25 | Version 26.0.1 26 | ============== 27 | 28 | - Added ``Recording.tracks`` relationship to the SQLAlchemy models. 29 | 30 | Version 26.0.0 31 | ============== 32 | 33 | - Support for MusicBrainz database schema 26. 34 | 35 | Version 25.0.4 36 | ============== 37 | 38 | - Fixed reading of MusicBrainz API token from ``mbslave.conf``. 39 | 40 | Version 25.0.3 41 | ============== 42 | 43 | - Fixed a bug in locating ``mbslave.conf``. 44 | 45 | Version 25.0.2 46 | ============== 47 | 48 | - Fixed database connection in ``mbslave``. 49 | 50 | Version 25.0.1 51 | ============== 52 | 53 | - Added ``mbdata.__version__``. 54 | - Fixed ``mbslave psql`` with custom PostgreSQL port number. 55 | - By default, the ``mbslave`` script will read its config file from either 56 | ``$PWD/mbslave.conf`` or ``/etc/mbslave.conf``. Previously, it was only ``$PWD/mbslave.conf``. 57 | - Documentation clarifications. 58 | 59 | Version 25.0.0 60 | ============== 61 | 62 | - Changed versioning with the Musicbrainz database schema as the major version. 63 | - Support for MusicBrainz database schema 25. 64 | - Added MusicBrainz replication (mbslave was merged into this project). 65 | - Docker image with mbslave. 66 | - Python 3 support. 67 | 68 | Version 2017.06.02 69 | ================== 70 | 71 | - Remove old_editor_name mapping. 72 | 73 | Version 2017.06.01 74 | ================== 75 | 76 | - Updated to MusicBrainz database schema 24. 77 | 78 | Version 2017.01.18 79 | ================== 80 | 81 | - Added index definitions to models. 82 | - Support for SQLAlchemy 1.1. 83 | 84 | Version 2016.07.17 85 | ================== 86 | 87 | - Updated to MusicBrainz database schema 23. 88 | - Python 3 support. 89 | 90 | Version 2016.02.11 91 | ================== 92 | 93 | - New function ``mbdata.config.configure()`` that makes sure that the 94 | models have not been imported yet. 95 | - Support for schema re-mapping in ``mbdata.config``. 96 | - Enum types are now correctly assigned to the schema. Previously they 97 | were schema-less. 98 | - New module ``mbdata.sample_data`` with a tiny sample of the 99 | MusicBrainz database useful for testing. 100 | 101 | Version 2015.06.20 102 | ================== 103 | 104 | - Added ``mbdata.config`` for configuring the SQLAlchemy base/metadata 105 | to be used in the models. 106 | 107 | Version 2015.01.10 108 | ================== 109 | 110 | - Initial release. 111 | -------------------------------------------------------------------------------- /DEVELOPMENT.rst: -------------------------------------------------------------------------------- 1 | ################# 2 | Development Guide 3 | ################# 4 | 5 | Development Setup 6 | ================= 7 | 8 | Clone the repository and setup virtualenv:: 9 | 10 | git clone git@github.com:metabrainz/mbdata.git 11 | cd mbdata/ 12 | virtualenv -p python3 venv 13 | source venv/bin/activate 14 | pip install poetry 15 | poetry install 16 | poetry self add 'poetry-dynamic-versioning[plugin]' 17 | 18 | Updating SQL files and models 19 | ============================= 20 | 21 | Run these scripts to update SQL files and rebuild SQLAlchemy models from them:: 22 | 23 | ./scripts/update_sql.sh $desired_git_branch_or_tag 24 | ./scripts/update_models.sh 25 | 26 | Release a new version 27 | ===================== 28 | 29 | 1. Add notes to ``CHANGELOG.rst`` 30 | 31 | 2. Create a new Github release. 32 | 33 | 3. The publish workflow will build a new package distribution and upload it to pypi. 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Lukas Lalinsky 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include mbdata/web/static * 2 | recursive-include mbdata/sql * 3 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ############################# 2 | MusicBrainz SQLAlchemy Models 3 | ############################# 4 | 5 | |pypi badge| 6 | 7 | .. |pypi badge| image:: https://badge.fury.io/py/mbdata.svg 8 | :target: https://badge.fury.io/py/mbdata 9 | 10 | If you are developing a Python application that needs access to the 11 | `MusicBrainz `__ 12 | `data `__, you can use 13 | the ``mbdata.models`` module to get 14 | `SQLAlchemy `__ models mapped to the 15 | MusicBrainz database tables. 16 | 17 | All tables from the MusicBrainz database are mapped, all foreign keys 18 | have one-way relationships set up and some models, where it's essential 19 | to access their related models, have two-way relationships (collections) 20 | set up. 21 | 22 | In order to work with the relationships efficiently, you should use the 23 | appropriate kind of `eager 24 | loading `__. 25 | 26 | Example usage of the models: 27 | 28 | .. code:: python 29 | 30 | >>> from sqlalchemy import create_engine 31 | >>> from sqlalchemy.orm import sessionmaker 32 | >>> from mbdata.models import Artist 33 | >>> engine = create_engine('postgresql://musicbrainz:musicbrainz@127.0.0.1/musicbrainz', echo=True) 34 | >>> Session = sessionmaker(bind=engine) 35 | >>> session = Session() 36 | >>> artist = session.query(Artist).filter_by(gid='8970d868-0723-483b-a75b-51088913d3d4').first() 37 | >>> print artist.name 38 | 39 | If you use the models in your own application and want to define foreign 40 | keys from your own models to the MusicBrainz schema, you will need to 41 | let ``mbdata`` know which metadata object to add the MusicBrainz tables 42 | to: 43 | 44 | .. code:: python 45 | 46 | from sqlalchemy.ext.declarative import declarative_base 47 | Base = declarative_base() 48 | 49 | # this should be the first place where you import anything from mbdata 50 | import mbdata.config 51 | mbdata.config.configure(base_class=Base) 52 | 53 | # now you can import and use the mbdata models 54 | import mbdata.models 55 | 56 | You can also use ``mbdata.config`` to re-map the MusicBrainz schema 57 | names, if your database doesn't follow the original structure: 58 | 59 | .. code:: python 60 | 61 | import mbdata.config 62 | mbdata.config.configure(schema='my_own_mb_schema') 63 | 64 | If you need sample MusicBrainz data for your tests, you can use 65 | ``mbdata.sample_data``: 66 | 67 | .. code:: python 68 | 69 | from mbdata.sample_data import create_sample_data 70 | create_sample_data(session) 71 | 72 | *********** 73 | Development 74 | *********** 75 | 76 | Normally you should work against a regular PostgreSQL database with 77 | MusicBrainz data, but for testing purposes, you can use a SQLite 78 | database with small data sub-set used in unit tests. You can create the 79 | database using: 80 | 81 | .. code:: sh 82 | 83 | ./bin/create_sample_db.py sample.db 84 | 85 | Then you can change your configuration: 86 | 87 | .. code:: sh 88 | 89 | DATABASE_URI = 'sqlite:///sample.db' 90 | 91 | Running tests: 92 | 93 | .. code:: sh 94 | 95 | pytest -v 96 | 97 | If you want to see the SQL queries from a failed test, you can use the 98 | following: 99 | 100 | .. code:: sh 101 | 102 | MBDATA_DATABASE_ECHO=1 pytest -v 103 | 104 | GitHub Actions workflow that automatically runs the tests after each commit is 105 | `here `__. 106 | -------------------------------------------------------------------------------- /check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | # poetry run isort --check mbdata/ 6 | # poetry run black --check mbdata/ 7 | 8 | poetry run flake8 mbdata 9 | poetry run pytest -v 10 | -------------------------------------------------------------------------------- /mbdata/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | # automatically filled in and updated by poetry-dynamic-versioning plugin 5 | # in distributions 6 | __version__ = "0.0.0" 7 | -------------------------------------------------------------------------------- /mbdata/api/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | -------------------------------------------------------------------------------- /mbdata/api/commonsettings.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | DATABASE_URI = '' 5 | DATABASE_ECHO = False 6 | 7 | SOLR_URI = 'http://127.0.0.1:8983/solr/musicbrainz' 8 | 9 | DEBUG = False 10 | 11 | -------------------------------------------------------------------------------- /mbdata/api/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | SUCCESS = 0 5 | INVALID_FORMAT_ERROR = 1 6 | MISSING_PARAMETER_ERROR = 2 7 | NOT_FOUND_ERROR = 3 8 | INCLUDE_DEPENDENCY_ERROR = 4 9 | INVALID_PARAMETER_ERROR = 5 10 | 11 | ERROR_STATUS_CODES = { 12 | SUCCESS: 200, 13 | NOT_FOUND_ERROR: 404, 14 | } 15 | 16 | ERROR_DEFAULT_STATUS_CODE = 400 17 | -------------------------------------------------------------------------------- /mbdata/api/includes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | import re 5 | import itertools 6 | from six import string_types 7 | from mbdata.utils.models import ENTITY_TYPES 8 | from typing import Set, Dict, Type 9 | 10 | 11 | def _iter_includes(tokens): 12 | if isinstance(tokens, string_types): 13 | yield tokens 14 | return 15 | 16 | includes = [''] 17 | for token in tokens: 18 | if token == ',': 19 | for include in includes: 20 | yield include 21 | includes = [''] 22 | else: 23 | new_includes = [] 24 | for prefix, suffix in itertools.product(includes, _iter_includes(token)): 25 | new_includes.append(prefix + suffix) 26 | includes = new_includes 27 | 28 | if includes != ['']: 29 | for include in includes: 30 | yield include 31 | 32 | 33 | def expand_includes(input): 34 | tokens = re.split(r'([,()])', input) 35 | 36 | groups = [[]] 37 | for token in tokens: 38 | if token == '(': 39 | groups.append([]) 40 | elif token == ')': 41 | group = groups.pop() 42 | groups[-1].append(group) 43 | elif token: 44 | groups[-1].append(token) 45 | grouped_tokens = groups.pop() 46 | 47 | return _iter_includes(grouped_tokens) 48 | 49 | 50 | def expand_includes_multi(inputs): 51 | return itertools.chain.from_iterable(map(expand_includes, inputs)) 52 | 53 | 54 | class Includes(object): 55 | INCLUDES = set([]) # type: Set[str] 56 | SUB_INCLUDES = {} # type: Dict[str, Type[Includes]] 57 | 58 | def __init__(self, includes=None, itself=True): 59 | self.includes = dict(includes or {}) 60 | for name in self.SUB_INCLUDES: 61 | if name in self.includes and not isinstance(self.includes[name], Includes): 62 | self.includes[name] = self.SUB_INCLUDES[name]() 63 | self.itself = itself 64 | 65 | def check(self, name): 66 | try: 67 | return getattr(self, name) 68 | except AttributeError: 69 | return False 70 | 71 | def __bool__(self): 72 | return self.itself 73 | 74 | __nonzero__ = __bool__ 75 | 76 | def __getattr__(self, name): 77 | if name not in self.INCLUDES and name not in self.SUB_INCLUDES: 78 | raise AttributeError(name) 79 | 80 | if name not in self.includes and name in self.SUB_INCLUDES: 81 | self.includes[name] = self.SUB_INCLUDES[name](itself=False) 82 | 83 | return self.includes.get(name, False) 84 | 85 | @classmethod 86 | def parse(cls, params, prefix=''): 87 | includes = {} 88 | sub_includes = {} 89 | 90 | for include in expand_includes_multi(params): 91 | if '.' in include: 92 | include, sub_include = include.split('.', 1) 93 | else: 94 | sub_include = None 95 | 96 | if include not in cls.INCLUDES and include not in cls.SUB_INCLUDES: 97 | raise ValueError('unknown include {0}{1}'.format(prefix, include)) 98 | 99 | includes[include] = True 100 | 101 | if sub_include is not None: 102 | if include not in cls.SUB_INCLUDES: 103 | raise ValueError("unknown include {0}{1}.{2}".format(prefix, include, sub_include)) 104 | sub_includes.setdefault(include, []).append(sub_include) 105 | 106 | for include, sub_params in sub_includes.items(): 107 | includes[include] = cls.SUB_INCLUDES[include].parse(sub_params, '{0}.'.format(include)) 108 | 109 | return cls(includes) 110 | 111 | 112 | class RelationshipsIncludes(Includes): 113 | INCLUDES = set(ENTITY_TYPES.keys()) 114 | 115 | 116 | class AreaIncludes(Includes): 117 | INCLUDES = set([ 118 | 'part_of', 119 | 'iso_3166', 120 | 'type', 121 | ]) 122 | 123 | 124 | class ArtistIncludes(Includes): 125 | INCLUDES = set([ 126 | 'ipi', 127 | 'isni', 128 | ]) 129 | 130 | SUB_INCLUDES = { 131 | 'areas': AreaIncludes, 132 | 'relationships': RelationshipsIncludes, 133 | } 134 | 135 | 136 | class LabelIncludes(Includes): 137 | INCLUDES = set([ 138 | 'ipi', 139 | 'isni', 140 | ]) 141 | 142 | SUB_INCLUDES = { 143 | 'area': AreaIncludes, 144 | 'relationships': RelationshipsIncludes, 145 | } 146 | 147 | 148 | class RecordingIncludes(Includes): 149 | INCLUDES = set([ 150 | 'artist', 151 | 'artists', 152 | 'isrc', 153 | ]) 154 | 155 | SUB_INCLUDES = { 156 | 'relationships': RelationshipsIncludes, 157 | } 158 | 159 | 160 | class TrackIncludes(Includes): 161 | INCLUDES = set([ 162 | 'artist', 163 | 'artists', 164 | ]) 165 | 166 | SUB_INCLUDES = { 167 | 'recording': RecordingIncludes, 168 | } 169 | 170 | 171 | class MediumIncludes(Includes): 172 | INCLUDES = set([]) # type: Set[str] 173 | 174 | SUB_INCLUDES = { 175 | 'tracks': TrackIncludes, 176 | } 177 | 178 | 179 | class ReleaseGroupIncludes(Includes): 180 | INCLUDES = set([ 181 | 'artist', 182 | 'artists', 183 | ]) 184 | 185 | SUB_INCLUDES = { 186 | 'relationships': RelationshipsIncludes, 187 | } 188 | 189 | 190 | class ReleaseIncludes(Includes): 191 | INCLUDES = set([ 192 | 'artist', 193 | 'artists', 194 | ]) 195 | 196 | SUB_INCLUDES = { 197 | 'mediums': MediumIncludes, 198 | 'release_group': ReleaseGroupIncludes, 199 | 'relationships': RelationshipsIncludes, 200 | } 201 | 202 | 203 | class WorkIncludes(Includes): 204 | INCLUDES = set([ 205 | 'iswc', 206 | ]) 207 | 208 | SUB_INCLUDES = { 209 | 'relationships': RelationshipsIncludes, 210 | } 211 | 212 | 213 | class PlaceIncludes(Includes): 214 | INCLUDES = set([]) # type: Set[str] 215 | 216 | SUB_INCLUDES = { 217 | 'area': AreaIncludes, 218 | 'relationships': RelationshipsIncludes, 219 | } 220 | 221 | 222 | class URLIncludes(Includes): 223 | INCLUDES = set([]) # type: Set[str] 224 | 225 | SUB_INCLUDES = { 226 | 'relationships': RelationshipsIncludes, 227 | } 228 | 229 | 230 | # this can't be defined directly in the class because of circular dependency 231 | RelationshipsIncludes.SUB_INCLUDES = { 232 | 'artist': ArtistIncludes, 233 | 'label': LabelIncludes, 234 | 'place': PlaceIncludes, 235 | 'recording': RecordingIncludes, 236 | 'release': ReleaseIncludes, 237 | 'release_group': ReleaseGroupIncludes, 238 | 'url': URLIncludes, 239 | 'work': WorkIncludes, 240 | } 241 | 242 | -------------------------------------------------------------------------------- /mbdata/config.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from typing import Dict 3 | 4 | # Override this if you want mbdata models to be based on your own base class 5 | Base = None 6 | 7 | # Override this if you want mbdata to create its own base class, but linked to your metadata object 8 | metadata = None 9 | 10 | # Override this if you want customize the schema names that mbdata uses 11 | schemas = {} # type: Dict[str, str] 12 | 13 | use_cube = True 14 | 15 | _is_frozen = False 16 | _unset = object() 17 | 18 | 19 | def configure(base_class=_unset, metadata=_unset, schema=_unset, schemas=_unset, use_cube=_unset): 20 | if _is_frozen: 21 | raise RuntimeError("mbdata.models was already imported, you can't configure it anymore") 22 | if base_class is not _unset: 23 | sys.modules[__name__].Base = base_class 24 | if metadata is not _unset: 25 | sys.modules[__name__].metadata = metadata 26 | if schemas is not _unset: 27 | sys.modules[__name__].schemas = schemas 28 | elif schema is not _unset: 29 | sys.modules[__name__].schemas = { 30 | 'musicbrainz': schema, 31 | 'cover_art_archive': schema, 32 | 'wikidocs': schema, 33 | 'statistics': schema, 34 | 'documentation': schema, 35 | } 36 | if use_cube is not _unset: 37 | sys.modules[__name__].use_cube = use_cube 38 | 39 | 40 | def freeze(): 41 | global _is_frozen 42 | _is_frozen = True 43 | -------------------------------------------------------------------------------- /mbdata/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metabrainz/mbdata/648c34e19327fbc12ccfec6f363f456315da1024/mbdata/data/__init__.py -------------------------------------------------------------------------------- /mbdata/data/artist.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | from sqlalchemy.orm import joinedload, subqueryload, defer 5 | from mbdata.models import ( 6 | Artist, 7 | ) 8 | from mbdata.api.data import ( 9 | query_artist, 10 | load_areas, 11 | load_links, 12 | ) 13 | from mbdata.api.serialize import ( 14 | serialize_artist, 15 | ) 16 | 17 | 18 | def get_artists_by_ids(db, ids, include): 19 | if not ids: 20 | return {} 21 | 22 | artists = query_artist(db, include).filter(Artist.id.in_(ids)).all() 23 | 24 | if include.areas: 25 | load_areas(db, artists, include.areas) 26 | 27 | if include.relationships: 28 | load_links(db, artists, include.relationships) 29 | 30 | results = {} 31 | for artist in artists: 32 | results[artist.id] = serialize_artist(artist, include) 33 | return results 34 | 35 | -------------------------------------------------------------------------------- /mbdata/data/label.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | from sqlalchemy.orm import joinedload, subqueryload, subqueryload_all, defer 5 | from mbdata.models import ( 6 | Label, 7 | ) 8 | from mbdata.api.data import ( 9 | query_label, 10 | load_areas, 11 | load_links, 12 | ) 13 | from mbdata.api.serialize import ( 14 | serialize_label, 15 | ) 16 | 17 | 18 | def get_labels_by_ids(db, ids, include): 19 | if not ids: 20 | return {} 21 | 22 | labels = query_label(db, include).filter(Label.id.in_(ids)).all() 23 | 24 | if include.relationships: 25 | load_links(db, labels, include.relationships) 26 | 27 | results = {} 28 | for label in labels: 29 | results[label.id] = serialize_label(label, include) 30 | return results 31 | 32 | -------------------------------------------------------------------------------- /mbdata/data/recording.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | from sqlalchemy.orm import joinedload, subqueryload, defer 5 | from mbdata.models import ( 6 | Recording, 7 | ) 8 | from mbdata.api.data import ( 9 | query_recording, 10 | load_links, 11 | ) 12 | from mbdata.api.serialize import ( 13 | serialize_recording, 14 | ) 15 | 16 | 17 | def get_recordings_by_ids(db, ids, include): 18 | if not ids: 19 | return {} 20 | 21 | recordings = query_recording(db, include).filter(Recording.id.in_(ids)).all() 22 | 23 | if include.relationships: 24 | load_links(db, recordings, include.relationships) 25 | 26 | results = {} 27 | for recording in recordings: 28 | results[recording.id] = serialize_recording(recording, include) 29 | return results 30 | 31 | -------------------------------------------------------------------------------- /mbdata/data/release_group.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | from sqlalchemy.orm import joinedload, subqueryload, defer 5 | from mbdata.models import ( 6 | ReleaseGroup, 7 | ) 8 | from mbdata.api.data import ( 9 | query_release_group, 10 | load_links, 11 | ) 12 | from mbdata.api.serialize import ( 13 | serialize_release_group, 14 | ) 15 | 16 | 17 | def get_release_groups_by_ids(db, ids, include): 18 | if not ids: 19 | return {} 20 | 21 | release_groups = query_release_group(db, include).filter(ReleaseGroup.id.in_(ids)).all() 22 | 23 | if include.relationships: 24 | load_links(db, release_groups, include.relationships) 25 | 26 | results = {} 27 | for release_group in release_groups: 28 | results[release_group.id] = serialize_release_group(release_group, include) 29 | return results 30 | 31 | -------------------------------------------------------------------------------- /mbdata/sql/CalculateRelatedTags.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | ---------------------------------------- 6 | -- Calculate maximum tag count for each entity, this is used 7 | -- later to weight relations between common tags. 8 | ---------------------------------------- 9 | 10 | CREATE TEMPORARY TABLE tmp_artist_tag_count 11 | ( 12 | id INTEGER NOT NULL, 13 | max_count INTEGER NOT NULL 14 | ); 15 | 16 | CREATE TEMPORARY TABLE tmp_release_tag_count 17 | ( 18 | id INTEGER NOT NULL, 19 | max_count INTEGER NOT NULL 20 | ); 21 | 22 | CREATE TEMPORARY TABLE tmp_label_tag_count 23 | ( 24 | id INTEGER NOT NULL, 25 | max_count INTEGER NOT NULL 26 | ); 27 | 28 | CREATE TEMPORARY TABLE tmp_recording_tag_count 29 | ( 30 | id INTEGER NOT NULL, 31 | max_count INTEGER NOT NULL 32 | ); 33 | 34 | 35 | INSERT INTO tmp_artist_tag_count SELECT 36 | a.id, MAX(t.count) AS max_count 37 | FROM 38 | artist a 39 | JOIN artist_tag t ON t.artist = a.id 40 | GROUP BY a.id; 41 | 42 | 43 | INSERT INTO tmp_release_tag_count SELECT 44 | r.id, MAX(t.count) AS max_count 45 | FROM 46 | release r 47 | JOIN release_tag t ON t.release = r.id 48 | GROUP BY r.id; 49 | 50 | 51 | INSERT INTO tmp_label_tag_count SELECT 52 | a.id, MAX(t.count) AS max_count 53 | FROM 54 | label a 55 | JOIN label_tag t ON t.label = a.id 56 | GROUP BY a.id; 57 | 58 | 59 | INSERT INTO tmp_recording_tag_count SELECT 60 | a.id, MAX(t.count) AS max_count 61 | FROM 62 | recording a 63 | JOIN recording_tag t ON t.recording = a.id 64 | GROUP BY a.id; 65 | 66 | 67 | CREATE UNIQUE INDEX tmp_artist_tag_count_id_idx ON tmp_artist_tag_count (id); 68 | CREATE UNIQUE INDEX tmp_release_tag_count_id_idx ON tmp_release_tag_count (id); 69 | CREATE UNIQUE INDEX tmp_label_tag_count_id_idx ON tmp_label_tag_count (id); 70 | CREATE UNIQUE INDEX tmp_recording_tag_count_id_idx ON tmp_recording_tag_count (id); 71 | 72 | 73 | ---------------------------------------- 74 | -- Calculate weighted relations between tags from common tags on entities. 75 | ---------------------------------------- 76 | 77 | 78 | CREATE TEMPORARY TABLE tmp_artist_tag_relation 79 | ( 80 | tag1 INTEGER NOT NULL, 81 | tag2 INTEGER NOT NULL, 82 | weight FLOAT NOT NULL 83 | ); 84 | 85 | CREATE TEMPORARY TABLE tmp_release_tag_relation 86 | ( 87 | tag1 INTEGER NOT NULL, 88 | tag2 INTEGER NOT NULL, 89 | weight FLOAT NOT NULL 90 | ); 91 | 92 | CREATE TEMPORARY TABLE tmp_label_tag_relation 93 | ( 94 | tag1 INTEGER NOT NULL, 95 | tag2 INTEGER NOT NULL, 96 | weight FLOAT NOT NULL 97 | ); 98 | 99 | CREATE TEMPORARY TABLE tmp_recording_tag_relation 100 | ( 101 | tag1 INTEGER NOT NULL, 102 | tag2 INTEGER NOT NULL, 103 | weight FLOAT NOT NULL 104 | ); 105 | 106 | CREATE TEMPORARY TABLE tmp_area_tag_relation 107 | ( 108 | tag1 INTEGER NOT NULL, 109 | tag2 INTEGER NOT NULL, 110 | weight FLOAT NOT NULL 111 | ); 112 | 113 | CREATE TEMPORARY TABLE tmp_instrument_tag_relation 114 | ( 115 | tag1 INTEGER NOT NULL, 116 | tag2 INTEGER NOT NULL, 117 | weight FLOAT NOT NULL 118 | ); 119 | 120 | CREATE TEMPORARY TABLE tmp_series_tag_relation 121 | ( 122 | tag1 INTEGER NOT NULL, 123 | tag2 INTEGER NOT NULL, 124 | weight FLOAT NOT NULL 125 | ); 126 | 127 | 128 | INSERT INTO tmp_artist_tag_relation SELECT 129 | t1.tag, t2.tag, 130 | SUM(((t1.count + t2.count) / 2.0) / tc.max_count) AS weight 131 | FROM 132 | artist a 133 | JOIN artist_tag t1 ON t1.artist = a.id 134 | JOIN artist_tag t2 ON t2.artist = a.id 135 | LEFT JOIN tmp_artist_tag_count tc ON a.id = tc.id 136 | WHERE t1.tag < t2.tag 137 | GROUP BY t1.tag, t2.tag 138 | HAVING COUNT(*) >= 3; 139 | 140 | 141 | INSERT INTO tmp_release_tag_relation SELECT 142 | t1.tag, t2.tag, 143 | SUM(((t1.count + t2.count) / 2.0) / tc.max_count) AS weight 144 | FROM 145 | release a 146 | JOIN release_tag t1 ON t1.release = a.id 147 | JOIN release_tag t2 ON t2.release = a.id 148 | LEFT JOIN tmp_release_tag_count tc ON a.id = tc.id 149 | WHERE t1.tag < t2.tag 150 | GROUP BY t1.tag, t2.tag 151 | HAVING COUNT(*) >= 3; 152 | 153 | 154 | INSERT INTO tmp_label_tag_relation SELECT 155 | t1.tag, t2.tag, 156 | SUM(((t1.count + t2.count) / 2.0) / tc.max_count) AS weight 157 | FROM 158 | label a 159 | JOIN label_tag t1 ON t1.label = a.id 160 | JOIN label_tag t2 ON t2.label = a.id 161 | LEFT JOIN tmp_label_tag_count tc ON a.id = tc.id 162 | WHERE t1.tag < t2.tag 163 | GROUP BY t1.tag, t2.tag 164 | HAVING COUNT(*) >= 3; 165 | 166 | 167 | INSERT INTO tmp_recording_tag_relation SELECT 168 | t1.tag, t2.tag, 169 | SUM(((t1.count + t2.count) / 2.0) / tc.max_count) AS weight 170 | FROM 171 | recording a 172 | JOIN recording_tag t1 ON t1.recording = a.id 173 | JOIN recording_tag t2 ON t2.recording = a.id 174 | LEFT JOIN tmp_recording_tag_count tc ON a.id = tc.id 175 | WHERE t1.tag < t2.tag 176 | GROUP BY t1.tag, t2.tag 177 | HAVING COUNT(*) >= 3; 178 | 179 | 180 | INSERT INTO tmp_area_tag_relation SELECT 181 | t1.tag, t2.tag, 182 | SUM(((t1.count + t2.count) / 2.0) / tc.max_count) AS weight 183 | FROM 184 | area a 185 | JOIN area_tag t1 ON t1.area = a.id 186 | JOIN area_tag t2 ON t2.area = a.id 187 | LEFT JOIN tmp_area_tag_count tc ON a.id = tc.id 188 | WHERE t1.tag < t2.tag 189 | GROUP BY t1.tag, t2.tag 190 | HAVING COUNT(*) >= 3; 191 | 192 | 193 | INSERT INTO tmp_instrument_tag_relation SELECT 194 | t1.tag, t2.tag, 195 | SUM(((t1.count + t2.count) / 2.0) / tc.max_count) AS weight 196 | FROM 197 | instrument a 198 | JOIN instrument_tag t1 ON t1.instrument = a.id 199 | JOIN instrument_tag t2 ON t2.instrument = a.id 200 | LEFT JOIN tmp_instrument_tag_count tc ON a.id = tc.id 201 | WHERE t1.tag < t2.tag 202 | GROUP BY t1.tag, t2.tag 203 | HAVING COUNT(*) >= 3; 204 | 205 | 206 | INSERT INTO tmp_series_tag_relation SELECT 207 | t1.tag, t2.tag, 208 | SUM(((t1.count + t2.count) / 2.0) / tc.max_count) AS weight 209 | FROM 210 | series a 211 | JOIN series_tag t1 ON t1.series = a.id 212 | JOIN series_tag t2 ON t2.series = a.id 213 | LEFT JOIN tmp_series_tag_count tc ON a.id = tc.id 214 | WHERE t1.tag < t2.tag 215 | GROUP BY t1.tag, t2.tag 216 | HAVING COUNT(*) >= 3; 217 | 218 | 219 | CREATE INDEX tmp_artist_tag_relation_tag1 ON tmp_artist_tag_relation (tag1); 220 | CREATE INDEX tmp_artist_tag_relation_tag2 ON tmp_artist_tag_relation (tag2); 221 | 222 | CREATE INDEX tmp_release_tag_relation_tag1 ON tmp_release_tag_relation (tag1); 223 | CREATE INDEX tmp_release_tag_relation_tag2 ON tmp_release_tag_relation (tag2); 224 | 225 | CREATE INDEX tmp_label_tag_relation_tag1 ON tmp_label_tag_relation (tag1); 226 | CREATE INDEX tmp_label_tag_relation_tag2 ON tmp_label_tag_relation (tag2); 227 | 228 | CREATE INDEX tmp_recording_tag_relation_tag1 ON tmp_recording_tag_relation (tag1); 229 | CREATE INDEX tmp_recording_tag_relation_tag2 ON tmp_recording_tag_relation (tag2); 230 | 231 | CREATE INDEX tmp_series_tag_relation_tag1 ON tmp_series_tag_relation (tag1); 232 | CREATE INDEX tmp_series_tag_relation_tag2 ON tmp_series_tag_relation (tag2); 233 | 234 | CREATE INDEX tmp_area_tag_relation_tag1 ON tmp_area_tag_relation (tag1); 235 | CREATE INDEX tmp_area_tag_relation_tag2 ON tmp_area_tag_relation (tag2); 236 | 237 | CREATE INDEX tmp_instrument_tag_relation_tag1 ON tmp_instrument_tag_relation (tag1); 238 | CREATE INDEX tmp_instrument_tag_relation_tag2 ON tmp_instrument_tag_relation (tag2); 239 | 240 | ---------------------------------------- 241 | -- Join the temporary table and calculate the final weights. 242 | ---------------------------------------- 243 | 244 | TRUNCATE tag_relation; 245 | 246 | INSERT INTO tag_relation SELECT 247 | COALESCE(r1.tag1, r2.tag1, r3.tag1, r4.tag1) AS tag1, 248 | COALESCE(r1.tag2, r2.tag2, r3.tag2, r4.tag2) AS tag2, 249 | COALESCE(r1.weight, 0) + COALESCE(r2.weight, 0) + COALESCE(r3.weight, 0) + COALESCE(r4.weight, 0) AS weight 250 | FROM 251 | tmp_artist_tag_relation r1 252 | FULL OUTER JOIN tmp_release_tag_relation r2 253 | ON (r2.tag1 = r1.tag1 AND r2.tag2 = r1.tag2) 254 | FULL OUTER JOIN tmp_label_tag_relation r3 255 | ON (r3.tag1 = COALESCE(r1.tag1, r2.tag1) AND r3.tag2 = COALESCE(r1.tag2, r2.tag2)) 256 | FULL OUTER JOIN tmp_recording_tag_relation r4 257 | ON (r4.tag1 = COALESCE(r1.tag1, r2.tag1, r3.tag1) AND r4.tag2 = COALESCE(r1.tag2, r2.tag2, r3.tag2)); 258 | 259 | /* 260 | 261 | Usage: 262 | 263 | SELECT 264 | t1.name, t2.name, tr.weight 265 | FROM 266 | tag t1 267 | JOIN tag_relation tr ON t1.id = tr.tag1 OR t1.id = tr.tag2 268 | JOIN tag t2 ON t1.id != t2.id AND (t2.id = tr.tag1 OR t2.id = tr.tag2) 269 | WHERE 270 | t1.name = 'jazz' 271 | ORDER BY tr.weight DESC; 272 | 273 | */ 274 | 275 | COMMIT; 276 | 277 | VACUUM ANALYZE tag_relation; 278 | -------------------------------------------------------------------------------- /mbdata/sql/CreateCollateIndexes.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | BEGIN; 3 | CREATE INDEX release_idx_musicbrainz_collate ON release (name COLLATE musicbrainz.musicbrainz); 4 | CREATE INDEX release_group_idx_musicbrainz_collate ON release_group (name COLLATE musicbrainz.musicbrainz); 5 | CREATE INDEX artist_idx_musicbrainz_collate ON artist (name COLLATE musicbrainz.musicbrainz); 6 | CREATE INDEX artist_credit_idx_musicbrainz_collate ON artist_credit (name COLLATE musicbrainz.musicbrainz); 7 | CREATE INDEX artist_credit_name_idx_musicbrainz_collate ON artist_credit_name (name COLLATE musicbrainz.musicbrainz); 8 | CREATE INDEX label_idx_musicbrainz_collate ON label (name COLLATE musicbrainz.musicbrainz); 9 | CREATE INDEX recording_idx_musicbrainz_collate ON recording (name COLLATE musicbrainz.musicbrainz); 10 | CREATE INDEX work_idx_musicbrainz_collate ON work (name COLLATE musicbrainz.musicbrainz); 11 | COMMIT; 12 | -------------------------------------------------------------------------------- /mbdata/sql/CreateCollations.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | SET search_path = musicbrainz, public; 4 | 5 | BEGIN; 6 | 7 | CREATE COLLATION musicbrainz ( 8 | provider = icu, 9 | locale = '@colCaseFirst=lower;colNumeric=yes' 10 | ); 11 | 12 | COMMIT; 13 | -------------------------------------------------------------------------------- /mbdata/sql/CreateMirrorIndexes.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | BEGIN; 3 | 4 | CREATE INDEX medium_idx_release_position ON medium (release, position); 5 | 6 | CREATE INDEX track_idx_medium_position ON track (medium, position); 7 | 8 | COMMIT; 9 | -------------------------------------------------------------------------------- /mbdata/sql/CreateMirrorOnlyFunctions.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | CREATE OR REPLACE FUNCTION a_ins_release_mirror() 6 | RETURNS trigger AS $$ 7 | BEGIN 8 | INSERT INTO artist_release_pending_update VALUES (NEW.id); 9 | INSERT INTO artist_release_group_pending_update VALUES (NEW.release_group); 10 | RETURN NULL; 11 | END; 12 | $$ LANGUAGE 'plpgsql'; 13 | 14 | CREATE OR REPLACE FUNCTION a_upd_release_mirror() 15 | RETURNS trigger AS $$ 16 | BEGIN 17 | IF ( 18 | NEW.status IS DISTINCT FROM OLD.status OR 19 | NEW.release_group != OLD.release_group OR 20 | NEW.artist_credit != OLD.artist_credit 21 | ) THEN 22 | INSERT INTO artist_release_group_pending_update 23 | VALUES (NEW.release_group), (OLD.release_group); 24 | END IF; 25 | IF ( 26 | NEW.barcode IS DISTINCT FROM OLD.barcode OR 27 | NEW.name != OLD.name OR 28 | NEW.artist_credit != OLD.artist_credit 29 | ) THEN 30 | INSERT INTO artist_release_pending_update VALUES (OLD.id); 31 | END IF; 32 | RETURN NULL; 33 | END; 34 | $$ LANGUAGE 'plpgsql'; 35 | 36 | CREATE OR REPLACE FUNCTION a_del_release_mirror() 37 | RETURNS trigger AS $$ 38 | BEGIN 39 | INSERT INTO artist_release_pending_update VALUES (OLD.id); 40 | INSERT INTO artist_release_group_pending_update VALUES (OLD.release_group); 41 | RETURN NULL; 42 | END; 43 | $$ LANGUAGE 'plpgsql'; 44 | 45 | CREATE OR REPLACE FUNCTION a_ins_release_event_mirror() 46 | RETURNS trigger AS $$ 47 | BEGIN 48 | PERFORM set_release_first_release_date(NEW.release); 49 | PERFORM set_releases_recordings_first_release_dates(ARRAY[NEW.release]); 50 | IF TG_TABLE_NAME = 'release_country' THEN 51 | INSERT INTO artist_release_pending_update VALUES (NEW.release); 52 | END IF; 53 | RETURN NULL; 54 | END; 55 | $$ LANGUAGE 'plpgsql'; 56 | 57 | CREATE OR REPLACE FUNCTION a_upd_release_event_mirror() 58 | RETURNS trigger AS $$ 59 | BEGIN 60 | PERFORM set_release_first_release_date(OLD.release); 61 | PERFORM set_release_first_release_date(NEW.release); 62 | PERFORM set_releases_recordings_first_release_dates(ARRAY[NEW.release, OLD.release]); 63 | IF TG_TABLE_NAME = 'release_country' THEN 64 | IF NEW.country != OLD.country THEN 65 | INSERT INTO artist_release_pending_update VALUES (OLD.release); 66 | END IF; 67 | END IF; 68 | RETURN NULL; 69 | END; 70 | $$ LANGUAGE 'plpgsql'; 71 | 72 | CREATE OR REPLACE FUNCTION a_del_release_event_mirror() 73 | RETURNS trigger AS $$ 74 | BEGIN 75 | PERFORM set_release_first_release_date(OLD.release); 76 | PERFORM set_releases_recordings_first_release_dates(ARRAY[OLD.release]); 77 | IF TG_TABLE_NAME = 'release_country' THEN 78 | INSERT INTO artist_release_pending_update VALUES (OLD.release); 79 | END IF; 80 | RETURN NULL; 81 | END; 82 | $$ LANGUAGE 'plpgsql'; 83 | 84 | CREATE OR REPLACE FUNCTION a_ins_release_group_mirror() 85 | RETURNS trigger AS $$ 86 | BEGIN 87 | INSERT INTO artist_release_group_pending_update VALUES (NEW.id); 88 | RETURN NULL; 89 | END; 90 | $$ LANGUAGE 'plpgsql'; 91 | 92 | CREATE OR REPLACE FUNCTION a_upd_release_group_mirror() 93 | RETURNS trigger AS $$ 94 | BEGIN 95 | IF ( 96 | NEW.name != OLD.name OR 97 | NEW.artist_credit != OLD.artist_credit OR 98 | NEW.type IS DISTINCT FROM OLD.type 99 | ) THEN 100 | INSERT INTO artist_release_group_pending_update VALUES (OLD.id); 101 | END IF; 102 | RETURN NULL; 103 | END; 104 | $$ LANGUAGE 'plpgsql'; 105 | 106 | CREATE OR REPLACE FUNCTION a_del_release_group_mirror() 107 | RETURNS trigger AS $$ 108 | BEGIN 109 | INSERT INTO artist_release_group_pending_update VALUES (OLD.id); 110 | RETURN NULL; 111 | END; 112 | $$ LANGUAGE 'plpgsql'; 113 | 114 | CREATE OR REPLACE FUNCTION a_upd_release_group_meta_mirror() 115 | RETURNS trigger AS $$ 116 | BEGIN 117 | IF ( 118 | (NEW.first_release_date_year IS DISTINCT FROM OLD.first_release_date_year) OR 119 | (NEW.first_release_date_month IS DISTINCT FROM OLD.first_release_date_month) OR 120 | (NEW.first_release_date_day IS DISTINCT FROM OLD.first_release_date_day) 121 | ) THEN 122 | INSERT INTO artist_release_group_pending_update VALUES (OLD.id); 123 | END IF; 124 | RETURN NULL; 125 | END; 126 | $$ LANGUAGE 'plpgsql'; 127 | 128 | CREATE OR REPLACE FUNCTION a_ins_release_group_secondary_type_join_mirror() 129 | RETURNS trigger AS $$ 130 | BEGIN 131 | INSERT INTO artist_release_group_pending_update VALUES (NEW.release_group); 132 | RETURN NULL; 133 | END; 134 | $$ LANGUAGE 'plpgsql'; 135 | 136 | CREATE OR REPLACE FUNCTION a_del_release_group_secondary_type_join_mirror() 137 | RETURNS trigger AS $$ 138 | BEGIN 139 | INSERT INTO artist_release_group_pending_update VALUES (OLD.release_group); 140 | RETURN NULL; 141 | END; 142 | $$ LANGUAGE 'plpgsql'; 143 | 144 | CREATE OR REPLACE FUNCTION a_ins_release_label_mirror() 145 | RETURNS trigger AS $$ 146 | BEGIN 147 | INSERT INTO artist_release_pending_update VALUES (NEW.release); 148 | RETURN NULL; 149 | END; 150 | $$ LANGUAGE 'plpgsql'; 151 | 152 | CREATE OR REPLACE FUNCTION a_upd_release_label_mirror() 153 | RETURNS trigger AS $$ 154 | BEGIN 155 | IF NEW.catalog_number IS DISTINCT FROM OLD.catalog_number THEN 156 | INSERT INTO artist_release_pending_update VALUES (OLD.release); 157 | END IF; 158 | RETURN NULL; 159 | END; 160 | $$ LANGUAGE 'plpgsql'; 161 | 162 | CREATE OR REPLACE FUNCTION a_del_release_label_mirror() 163 | RETURNS trigger AS $$ 164 | BEGIN 165 | INSERT INTO artist_release_pending_update VALUES (OLD.release); 166 | RETURN NULL; 167 | END; 168 | $$ LANGUAGE 'plpgsql'; 169 | 170 | CREATE OR REPLACE FUNCTION a_ins_track_mirror() 171 | RETURNS trigger AS $$ 172 | BEGIN 173 | PERFORM set_recordings_first_release_dates(ARRAY[NEW.recording]); 174 | INSERT INTO artist_release_pending_update ( 175 | SELECT release FROM medium 176 | WHERE id = NEW.medium 177 | ); 178 | INSERT INTO artist_release_group_pending_update ( 179 | SELECT release_group FROM release 180 | JOIN medium ON medium.release = release.id 181 | WHERE medium.id = NEW.medium 182 | ); 183 | RETURN NULL; 184 | END; 185 | $$ LANGUAGE 'plpgsql'; 186 | 187 | CREATE OR REPLACE FUNCTION a_upd_track_mirror() 188 | RETURNS trigger AS $$ 189 | BEGIN 190 | IF NEW.artist_credit != OLD.artist_credit THEN 191 | INSERT INTO artist_release_pending_update ( 192 | SELECT release FROM medium 193 | WHERE id = OLD.medium 194 | ); 195 | INSERT INTO artist_release_group_pending_update ( 196 | SELECT release_group FROM release 197 | JOIN medium ON medium.release = release.id 198 | WHERE medium.id = OLD.medium 199 | ); 200 | END IF; 201 | IF OLD.recording <> NEW.recording THEN 202 | PERFORM set_recordings_first_release_dates(ARRAY[OLD.recording, NEW.recording]); 203 | END IF; 204 | RETURN NULL; 205 | END; 206 | $$ LANGUAGE 'plpgsql'; 207 | 208 | CREATE OR REPLACE FUNCTION a_del_track_mirror() 209 | RETURNS trigger AS $$ 210 | BEGIN 211 | PERFORM set_recordings_first_release_dates(ARRAY[OLD.recording]); 212 | INSERT INTO artist_release_pending_update ( 213 | SELECT release FROM medium 214 | WHERE id = OLD.medium 215 | ); 216 | INSERT INTO artist_release_group_pending_update ( 217 | SELECT release_group FROM release 218 | JOIN medium ON medium.release = release.id 219 | WHERE medium.id = OLD.medium 220 | ); 221 | RETURN NULL; 222 | END; 223 | $$ LANGUAGE 'plpgsql'; 224 | 225 | COMMIT; 226 | -------------------------------------------------------------------------------- /mbdata/sql/CreateMirrorOnlyTriggers.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | -- This file contains triggers that are necessary (and safe) to create 4 | -- on mirror databases. These are NOT created on master/standalone 5 | -- databases. 6 | -- 7 | -- The primary use case is to allow materialized tables to be kept 8 | -- up-to-date on mirrors without having to replicate that information. 9 | -- Since the materialized information can be fully derived from primary 10 | -- table data, we avoid packet bloat this way. 11 | -- 12 | -- Any functions these call should NEVER modify a replicated table! As 13 | -- a convention, functions that are safe to call here generally end in 14 | -- `_mirror`. 15 | 16 | BEGIN; 17 | 18 | CREATE TRIGGER a_ins_l_area_area_mirror AFTER INSERT ON l_area_area 19 | FOR EACH ROW EXECUTE PROCEDURE a_ins_l_area_area_mirror(); 20 | 21 | CREATE TRIGGER a_upd_l_area_area_mirror AFTER UPDATE ON l_area_area 22 | FOR EACH ROW EXECUTE PROCEDURE a_upd_l_area_area_mirror(); 23 | 24 | CREATE TRIGGER a_del_l_area_area_mirror AFTER DELETE ON l_area_area 25 | FOR EACH ROW EXECUTE PROCEDURE a_del_l_area_area_mirror(); 26 | 27 | CREATE TRIGGER a_upd_medium AFTER UPDATE ON medium 28 | FOR EACH ROW EXECUTE PROCEDURE a_upd_medium_mirror(); 29 | 30 | CREATE TRIGGER a_ins_release_mirror AFTER INSERT ON release 31 | FOR EACH ROW EXECUTE PROCEDURE a_ins_release_mirror(); 32 | 33 | CREATE TRIGGER a_upd_release_mirror AFTER UPDATE ON release 34 | FOR EACH ROW EXECUTE PROCEDURE a_upd_release_mirror(); 35 | 36 | CREATE TRIGGER a_del_release_mirror AFTER DELETE ON release 37 | FOR EACH ROW EXECUTE PROCEDURE a_del_release_mirror(); 38 | 39 | CREATE TRIGGER a_ins_release_event_mirror AFTER INSERT ON release_country 40 | FOR EACH ROW EXECUTE PROCEDURE a_ins_release_event_mirror(); 41 | 42 | CREATE TRIGGER a_upd_release_event_mirror AFTER UPDATE ON release_country 43 | FOR EACH ROW EXECUTE PROCEDURE a_upd_release_event_mirror(); 44 | 45 | CREATE TRIGGER a_del_release_event_mirror AFTER DELETE ON release_country 46 | FOR EACH ROW EXECUTE PROCEDURE a_del_release_event_mirror(); 47 | 48 | CREATE TRIGGER a_ins_release_event_mirror AFTER INSERT ON release_unknown_country 49 | FOR EACH ROW EXECUTE PROCEDURE a_ins_release_event_mirror(); 50 | 51 | CREATE TRIGGER a_upd_release_event_mirror AFTER UPDATE ON release_unknown_country 52 | FOR EACH ROW EXECUTE PROCEDURE a_upd_release_event_mirror(); 53 | 54 | CREATE TRIGGER a_del_release_event_mirror AFTER DELETE ON release_unknown_country 55 | FOR EACH ROW EXECUTE PROCEDURE a_del_release_event_mirror(); 56 | 57 | CREATE TRIGGER a_ins_release_group_mirror AFTER INSERT ON release_group 58 | FOR EACH ROW EXECUTE PROCEDURE a_ins_release_group_mirror(); 59 | 60 | CREATE TRIGGER a_upd_release_group_mirror AFTER UPDATE ON release_group 61 | FOR EACH ROW EXECUTE PROCEDURE a_upd_release_group_mirror(); 62 | 63 | CREATE TRIGGER a_del_release_group_mirror AFTER DELETE ON release_group 64 | FOR EACH ROW EXECUTE PROCEDURE a_del_release_group_mirror(); 65 | 66 | CREATE TRIGGER a_upd_release_group_meta_mirror AFTER UPDATE ON release_group_meta 67 | FOR EACH ROW EXECUTE PROCEDURE a_upd_release_group_meta_mirror(); 68 | 69 | CREATE TRIGGER a_upd_release_group_primary_type_mirror AFTER UPDATE ON release_group_primary_type 70 | FOR EACH ROW EXECUTE PROCEDURE a_upd_release_group_primary_type_mirror(); 71 | 72 | CREATE TRIGGER a_upd_release_group_secondary_type_mirror AFTER UPDATE ON release_group_secondary_type 73 | FOR EACH ROW EXECUTE PROCEDURE a_upd_release_group_secondary_type_mirror(); 74 | 75 | CREATE TRIGGER a_ins_release_group_secondary_type_join_mirror AFTER INSERT ON release_group_secondary_type_join 76 | FOR EACH ROW EXECUTE PROCEDURE a_ins_release_group_secondary_type_join_mirror(); 77 | 78 | CREATE TRIGGER a_del_release_group_secondary_type_join_mirror AFTER DELETE ON release_group_secondary_type_join 79 | FOR EACH ROW EXECUTE PROCEDURE a_del_release_group_secondary_type_join_mirror(); 80 | 81 | CREATE TRIGGER a_ins_release_label_mirror AFTER INSERT ON release_label 82 | FOR EACH ROW EXECUTE PROCEDURE a_ins_release_label_mirror(); 83 | 84 | CREATE TRIGGER a_upd_release_label_mirror AFTER UPDATE ON release_label 85 | FOR EACH ROW EXECUTE PROCEDURE a_upd_release_label_mirror(); 86 | 87 | CREATE TRIGGER a_del_release_label_mirror AFTER DELETE ON release_label 88 | FOR EACH ROW EXECUTE PROCEDURE a_del_release_label_mirror(); 89 | 90 | CREATE TRIGGER a_ins_track_mirror AFTER INSERT ON track 91 | FOR EACH ROW EXECUTE PROCEDURE a_ins_track_mirror(); 92 | 93 | CREATE TRIGGER a_upd_track_mirror AFTER UPDATE ON track 94 | FOR EACH ROW EXECUTE PROCEDURE a_upd_track_mirror(); 95 | 96 | CREATE TRIGGER a_del_track_mirror AFTER DELETE ON track 97 | FOR EACH ROW EXECUTE PROCEDURE a_del_track_mirror(); 98 | 99 | CREATE CONSTRAINT TRIGGER apply_artist_release_group_pending_updates_mirror 100 | AFTER INSERT OR UPDATE OR DELETE ON release DEFERRABLE INITIALLY DEFERRED 101 | FOR EACH ROW EXECUTE PROCEDURE apply_artist_release_group_pending_updates(); 102 | 103 | CREATE CONSTRAINT TRIGGER apply_artist_release_pending_updates_mirror 104 | AFTER INSERT OR UPDATE OR DELETE ON release DEFERRABLE INITIALLY DEFERRED 105 | FOR EACH ROW EXECUTE PROCEDURE apply_artist_release_pending_updates(); 106 | 107 | CREATE CONSTRAINT TRIGGER apply_artist_release_pending_updates_mirror 108 | AFTER INSERT OR UPDATE OR DELETE ON release_country DEFERRABLE INITIALLY DEFERRED 109 | FOR EACH ROW EXECUTE PROCEDURE apply_artist_release_pending_updates(); 110 | 111 | CREATE CONSTRAINT TRIGGER apply_artist_release_pending_updates_mirror 112 | AFTER INSERT OR UPDATE OR DELETE ON release_first_release_date DEFERRABLE INITIALLY DEFERRED 113 | FOR EACH ROW EXECUTE PROCEDURE apply_artist_release_pending_updates(); 114 | 115 | CREATE CONSTRAINT TRIGGER apply_artist_release_group_pending_updates_mirror 116 | AFTER INSERT OR UPDATE OR DELETE ON release_group DEFERRABLE INITIALLY DEFERRED 117 | FOR EACH ROW EXECUTE PROCEDURE apply_artist_release_group_pending_updates(); 118 | 119 | CREATE CONSTRAINT TRIGGER apply_artist_release_group_pending_updates_mirror 120 | AFTER UPDATE ON release_group_meta DEFERRABLE INITIALLY DEFERRED 121 | FOR EACH ROW EXECUTE PROCEDURE apply_artist_release_group_pending_updates(); 122 | 123 | CREATE CONSTRAINT TRIGGER apply_artist_release_group_pending_updates_mirror 124 | AFTER UPDATE ON release_group_primary_type DEFERRABLE INITIALLY DEFERRED 125 | FOR EACH ROW 126 | WHEN (OLD.child_order IS DISTINCT FROM NEW.child_order) 127 | EXECUTE PROCEDURE apply_artist_release_group_pending_updates(); 128 | 129 | CREATE CONSTRAINT TRIGGER apply_artist_release_group_pending_updates_mirror 130 | AFTER UPDATE ON release_group_secondary_type DEFERRABLE INITIALLY DEFERRED 131 | FOR EACH ROW 132 | WHEN (OLD.child_order IS DISTINCT FROM NEW.child_order) 133 | EXECUTE PROCEDURE apply_artist_release_group_pending_updates(); 134 | 135 | CREATE CONSTRAINT TRIGGER apply_artist_release_group_pending_updates_mirror 136 | AFTER INSERT OR DELETE ON release_group_secondary_type_join DEFERRABLE INITIALLY DEFERRED 137 | FOR EACH ROW EXECUTE PROCEDURE apply_artist_release_group_pending_updates(); 138 | 139 | CREATE CONSTRAINT TRIGGER apply_artist_release_pending_updates_mirror 140 | AFTER INSERT OR UPDATE OR DELETE ON release_label DEFERRABLE INITIALLY DEFERRED 141 | FOR EACH ROW EXECUTE PROCEDURE apply_artist_release_pending_updates(); 142 | 143 | CREATE CONSTRAINT TRIGGER apply_artist_release_group_pending_updates_mirror 144 | AFTER INSERT OR UPDATE OR DELETE ON track DEFERRABLE INITIALLY DEFERRED 145 | FOR EACH ROW EXECUTE PROCEDURE apply_artist_release_group_pending_updates(); 146 | 147 | CREATE CONSTRAINT TRIGGER apply_artist_release_pending_updates_mirror 148 | AFTER INSERT OR UPDATE OR DELETE ON track DEFERRABLE INITIALLY DEFERRED 149 | FOR EACH ROW EXECUTE PROCEDURE apply_artist_release_pending_updates(); 150 | 151 | COMMIT; 152 | -------------------------------------------------------------------------------- /mbdata/sql/CreateSearchConfiguration.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | SET search_path = musicbrainz, public; 4 | 5 | BEGIN; 6 | 7 | CREATE TEXT SEARCH CONFIGURATION mb_simple (COPY = pg_catalog.simple); 8 | ALTER TEXT SEARCH CONFIGURATION mb_simple 9 | ALTER MAPPING FOR word, numword, hword, numhword, hword_part, hword_numpart 10 | WITH unaccent, simple; 11 | 12 | COMMIT; 13 | -------------------------------------------------------------------------------- /mbdata/sql/CreateSearchIndexes.sql: -------------------------------------------------------------------------------- 1 | \unset ON_ERROR_STOP 2 | 3 | CREATE INDEX artist_idx_txt ON artist USING gin(musicbrainz.mb_simple_tsvector(name)); 4 | CREATE INDEX artist_idx_txt_sort ON artist USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 5 | 6 | CREATE INDEX artist_alias_idx_txt ON artist_alias USING gin(musicbrainz.mb_simple_tsvector(name)); 7 | CREATE INDEX artist_alias_idx_txt_sort ON artist_alias USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 8 | 9 | CREATE INDEX artist_credit_idx_txt ON artist_credit USING gin(musicbrainz.mb_simple_tsvector(name)); 10 | CREATE INDEX artist_credit_name_idx_txt ON artist_credit_name USING gin(musicbrainz.mb_simple_tsvector(name)); 11 | 12 | CREATE INDEX event_idx_txt ON event USING gin(musicbrainz.mb_simple_tsvector(name)); 13 | 14 | CREATE INDEX event_alias_idx_txt ON event_alias USING gin(musicbrainz.mb_simple_tsvector(name)); 15 | CREATE INDEX event_alias_idx_txt_sort ON event_alias USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 16 | 17 | CREATE INDEX instrument_idx_txt ON instrument USING gin(musicbrainz.mb_simple_tsvector(name)); 18 | 19 | CREATE INDEX label_idx_txt ON label USING gin(musicbrainz.mb_simple_tsvector(name)); 20 | 21 | CREATE INDEX label_alias_idx_txt ON label_alias USING gin(musicbrainz.mb_simple_tsvector(name)); 22 | CREATE INDEX label_alias_idx_txt_sort ON label_alias USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 23 | 24 | CREATE INDEX release_idx_txt ON release USING gin(musicbrainz.mb_simple_tsvector(name)); 25 | 26 | CREATE INDEX release_alias_idx_txt ON release_alias USING gin(musicbrainz.mb_simple_tsvector(name)); 27 | CREATE INDEX release_alias_idx_txt_sort ON release_alias USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 28 | 29 | CREATE INDEX release_group_idx_txt ON release_group USING gin(musicbrainz.mb_simple_tsvector(name)); 30 | 31 | CREATE INDEX release_group_alias_idx_txt ON release_group_alias USING gin(musicbrainz.mb_simple_tsvector(name)); 32 | CREATE INDEX release_group_alias_idx_txt_sort ON release_group_alias USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 33 | 34 | CREATE INDEX recording_idx_txt ON recording USING gin(musicbrainz.mb_simple_tsvector(name)); 35 | 36 | CREATE INDEX recording_alias_idx_txt ON recording_alias USING gin(musicbrainz.mb_simple_tsvector(name)); 37 | CREATE INDEX recording_alias_idx_txt_sort ON recording_alias USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 38 | 39 | CREATE INDEX series_idx_txt ON series USING gin(musicbrainz.mb_simple_tsvector(name)); 40 | 41 | CREATE INDEX series_alias_idx_txt ON series_alias USING gin(musicbrainz.mb_simple_tsvector(name)); 42 | CREATE INDEX series_alias_idx_txt_sort ON series_alias USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 43 | 44 | CREATE INDEX work_idx_txt ON work USING gin(musicbrainz.mb_simple_tsvector(name)); 45 | 46 | CREATE INDEX work_alias_idx_txt ON work_alias USING gin(musicbrainz.mb_simple_tsvector(name)); 47 | CREATE INDEX work_alias_idx_txt_sort ON work_alias USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 48 | 49 | CREATE INDEX area_idx_name_txt ON area USING gin(musicbrainz.mb_simple_tsvector(name)); 50 | 51 | CREATE INDEX area_alias_idx_txt ON area_alias USING gin(musicbrainz.mb_simple_tsvector(name)); 52 | CREATE INDEX area_alias_idx_txt_sort ON area_alias USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 53 | 54 | CREATE INDEX place_idx_name_txt ON place USING gin(musicbrainz.mb_simple_tsvector(name)); 55 | 56 | CREATE INDEX place_alias_idx_txt ON place_alias USING gin(musicbrainz.mb_simple_tsvector(name)); 57 | CREATE INDEX place_alias_idx_txt_sort ON place_alias USING gin(musicbrainz.mb_simple_tsvector(sort_name)); 58 | 59 | CREATE INDEX tag_idx_name_txt ON tag USING gin(musicbrainz.mb_simple_tsvector(name)); 60 | -------------------------------------------------------------------------------- /mbdata/sql/CreateTypes.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | BEGIN; 3 | 4 | CREATE TYPE cover_art_presence AS ENUM ('absent', 'present', 'darkened'); 5 | 6 | CREATE TYPE edit_note_status AS ENUM ('deleted', 'edited'); 7 | 8 | CREATE TYPE event_art_presence AS ENUM ('absent', 'present', 'darkened'); 9 | 10 | CREATE TYPE fluency AS ENUM ( 11 | 'basic', 12 | 'intermediate', 13 | 'advanced', 14 | 'native' 15 | ); 16 | 17 | CREATE TYPE oauth_code_challenge_method AS ENUM ('plain', 'S256'); 18 | 19 | CREATE TYPE ratable_entity_type AS ENUM ( 20 | 'artist', 21 | 'event', 22 | 'label', 23 | 'place', 24 | 'recording', 25 | 'release_group', 26 | 'work' 27 | ); 28 | 29 | CREATE TYPE taggable_entity_type AS ENUM ( 30 | 'area', 31 | 'artist', 32 | 'event', 33 | 'instrument', 34 | 'label', 35 | 'place', 36 | 'recording', 37 | 'release', 38 | 'release_group', 39 | 'series', 40 | 'work' 41 | ); 42 | 43 | COMMIT; 44 | -------------------------------------------------------------------------------- /mbdata/sql/CreateViews.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | CREATE OR REPLACE VIEW release_event AS 6 | SELECT 7 | release, date_year, date_month, date_day, country 8 | FROM ( 9 | SELECT release, date_year, date_month, date_day, country 10 | FROM release_country 11 | UNION ALL 12 | SELECT release, date_year, date_month, date_day, NULL 13 | FROM release_unknown_country 14 | ) as q; 15 | 16 | CREATE OR REPLACE VIEW artist_series AS 17 | SELECT entity0 AS artist, 18 | entity1 AS series, 19 | las.id AS relationship, 20 | link_order, 21 | las.link, 22 | COALESCE(text_value, '') AS text_value 23 | FROM l_artist_series las 24 | JOIN series s ON s.id = las.entity1 25 | JOIN link l ON l.id = las.link 26 | JOIN link_type lt ON (lt.id = l.link_type AND lt.gid = 'd1a845d1-8c03-3191-9454-e4e8d37fa5e0') 27 | LEFT OUTER JOIN link_attribute_text_value latv ON (latv.attribute_type = 788 AND latv.link = l.id) 28 | ORDER BY series, link_order; 29 | 30 | CREATE OR REPLACE VIEW event_series AS 31 | SELECT entity0 AS event, 32 | entity1 AS series, 33 | lrs.id AS relationship, 34 | link_order, 35 | lrs.link, 36 | COALESCE(text_value, '') AS text_value 37 | FROM l_event_series lrs 38 | JOIN series s ON s.id = lrs.entity1 39 | JOIN link l ON l.id = lrs.link 40 | JOIN link_type lt ON (lt.id = l.link_type AND lt.gid = '707d947d-9563-328a-9a7d-0c5b9c3a9791') 41 | LEFT OUTER JOIN link_attribute_text_value latv ON (latv.attribute_type = 788 AND latv.link = l.id) 42 | ORDER BY series, link_order; 43 | 44 | CREATE OR REPLACE VIEW recording_series AS 45 | SELECT entity0 AS recording, 46 | entity1 AS series, 47 | lrs.id AS relationship, 48 | link_order, 49 | lrs.link, 50 | COALESCE(text_value, '') AS text_value 51 | FROM l_recording_series lrs 52 | JOIN series s ON s.id = lrs.entity1 53 | JOIN link l ON l.id = lrs.link 54 | JOIN link_type lt ON (lt.id = l.link_type AND lt.gid = 'ea6f0698-6782-30d6-b16d-293081b66774') 55 | LEFT OUTER JOIN link_attribute_text_value latv ON (latv.attribute_type = 788 AND latv.link = l.id) 56 | ORDER BY series, link_order; 57 | 58 | CREATE OR REPLACE VIEW release_series AS 59 | SELECT entity0 AS release, 60 | entity1 AS series, 61 | lrs.id AS relationship, 62 | link_order, 63 | lrs.link, 64 | COALESCE(text_value, '') AS text_value 65 | FROM l_release_series lrs 66 | JOIN series s ON s.id = lrs.entity1 67 | JOIN link l ON l.id = lrs.link 68 | JOIN link_type lt ON (lt.id = l.link_type AND lt.gid = '3fa29f01-8e13-3e49-9b0a-ad212aa2f81d') 69 | LEFT OUTER JOIN link_attribute_text_value latv ON (latv.attribute_type = 788 AND latv.link = l.id) 70 | ORDER BY series, link_order; 71 | 72 | CREATE OR REPLACE VIEW release_group_series AS 73 | SELECT entity0 AS release_group, 74 | entity1 AS series, 75 | lrgs.id AS relationship, 76 | link_order, 77 | lrgs.link, 78 | COALESCE(text_value, '') AS text_value 79 | FROM l_release_group_series lrgs 80 | JOIN series s ON s.id = lrgs.entity1 81 | JOIN link l ON l.id = lrgs.link 82 | JOIN link_type lt ON (lt.id = l.link_type AND lt.gid = '01018437-91d8-36b9-bf89-3f885d53b5bd') 83 | LEFT OUTER JOIN link_attribute_text_value latv ON (latv.attribute_type = 788 AND latv.link = l.id) 84 | ORDER BY series, link_order; 85 | 86 | CREATE OR REPLACE VIEW work_series AS 87 | SELECT entity1 AS work, 88 | entity0 AS series, 89 | lsw.id AS relationship, 90 | link_order, 91 | lsw.link, 92 | COALESCE(text_value, '') AS text_value 93 | FROM l_series_work lsw 94 | JOIN series s ON s.id = lsw.entity0 95 | JOIN link l ON l.id = lsw.link 96 | JOIN link_type lt ON (lt.id = l.link_type AND lt.gid = 'b0d44366-cdf0-3acb-bee6-0f65a77a6ef0') 97 | LEFT OUTER JOIN link_attribute_text_value latv ON (latv.attribute_type = 788 AND latv.link = l.id) 98 | ORDER BY series, link_order; 99 | 100 | CREATE OR REPLACE VIEW medium_track_durations AS 101 | SELECT 102 | medium.id AS medium, 103 | array_agg(track.length ORDER BY track.position) FILTER (WHERE track.position = 0) AS pregap_length, 104 | array_agg(track.length ORDER BY track.position) FILTER (WHERE track.position > 0 AND track.is_data_track = false) AS cdtoc_track_lengths, 105 | array_agg(track.length ORDER BY track.position) FILTER (WHERE track.is_data_track = true) AS data_track_lengths 106 | FROM medium 107 | JOIN track ON track.medium = medium.id 108 | GROUP BY medium.id; 109 | 110 | COMMIT; 111 | 112 | -- vi: set ts=4 sw=4 et : 113 | -------------------------------------------------------------------------------- /mbdata/sql/DisableLastUpdatedTriggers.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | DO $$ 6 | DECLARE 7 | r record; 8 | BEGIN 9 | FOR r IN ( 10 | SELECT * 11 | FROM information_schema.triggers 12 | WHERE action_statement LIKE '%b_upd_last_updated_table%' 13 | ) LOOP 14 | EXECUTE 'ALTER TABLE ' || 15 | quote_ident(r.event_object_schema) || '.' || 16 | quote_ident(r.event_object_table) || 17 | ' DISABLE TRIGGER ' || 18 | quote_ident(r.trigger_name); 19 | END LOOP; 20 | END $$; 21 | 22 | COMMIT; 23 | -------------------------------------------------------------------------------- /mbdata/sql/DropAll.sql: -------------------------------------------------------------------------------- 1 | \unset ON_ERROR_STOP 2 | 3 | -- This script is a really quick and dirty way to tear down a database. 4 | -- It's really just a debug / development tool. 5 | 6 | \i admin/sql/DropReplicationTriggers.sql 7 | \i admin/sql/DropTriggers.sql 8 | \i admin/sql/DropMirrorOnlyTriggers.sql 9 | \i admin/sql/DropFunctions.sql 10 | \i admin/sql/DropViews.sql 11 | \i admin/sql/DropFKConstraints.sql 12 | \i admin/sql/DropIndexes.sql 13 | \i admin/sql/DropPrimaryKeys.sql 14 | \i admin/sql/DropTables.sql 15 | \i admin/sql/DropTypes.sql 16 | \i admin/sql/DropCollations.sql 17 | -------------------------------------------------------------------------------- /mbdata/sql/DropCollateIndexes.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | DROP INDEX artist_credit_idx_musicbrainz_collate; 3 | DROP INDEX artist_credit_name_idx_musicbrainz_collate; 4 | DROP INDEX artist_idx_musicbrainz_collate; 5 | DROP INDEX label_idx_musicbrainz_collate; 6 | DROP INDEX recording_idx_musicbrainz_collate; 7 | DROP INDEX release_group_idx_musicbrainz_collate; 8 | DROP INDEX release_idx_musicbrainz_collate; 9 | DROP INDEX work_idx_musicbrainz_collate; 10 | -------------------------------------------------------------------------------- /mbdata/sql/DropCollations.sql: -------------------------------------------------------------------------------- 1 | \unset ON_ERROR_STOP 2 | 3 | DROP COLLATION musicbrainz; 4 | -------------------------------------------------------------------------------- /mbdata/sql/DropFunctions.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | DROP FUNCTION _median(INTEGER[]); 5 | DROP FUNCTION a_del_alternative_medium_track(); 6 | DROP FUNCTION a_del_alternative_release_or_track(); 7 | DROP FUNCTION a_del_instrument(); 8 | DROP FUNCTION a_del_l_area_area_mirror(); 9 | DROP FUNCTION a_del_recording(); 10 | DROP FUNCTION a_del_release(); 11 | DROP FUNCTION a_del_release_event(); 12 | DROP FUNCTION a_del_release_group(); 13 | DROP FUNCTION a_del_release_group_secondary_type_join(); 14 | DROP FUNCTION a_del_release_label(); 15 | DROP FUNCTION a_del_track(); 16 | DROP FUNCTION a_ins_alternative_medium_track(); 17 | DROP FUNCTION a_ins_alternative_release_or_track(); 18 | DROP FUNCTION a_ins_artist(); 19 | DROP FUNCTION a_ins_edit_note(); 20 | DROP FUNCTION a_ins_event(); 21 | DROP FUNCTION a_ins_instrument(); 22 | DROP FUNCTION a_ins_l_area_area_mirror(); 23 | DROP FUNCTION a_ins_label(); 24 | DROP FUNCTION a_ins_place(); 25 | DROP FUNCTION a_ins_recording(); 26 | DROP FUNCTION a_ins_release(); 27 | DROP FUNCTION a_ins_release_event(); 28 | DROP FUNCTION a_ins_release_group(); 29 | DROP FUNCTION a_ins_release_group_secondary_type_join(); 30 | DROP FUNCTION a_ins_release_label(); 31 | DROP FUNCTION a_ins_track(); 32 | DROP FUNCTION a_ins_work(); 33 | DROP FUNCTION a_upd_alternative_medium_track(); 34 | DROP FUNCTION a_upd_alternative_release_or_track(); 35 | DROP FUNCTION a_upd_edit(); 36 | DROP FUNCTION a_upd_instrument(); 37 | DROP FUNCTION a_upd_l_area_area_mirror(); 38 | DROP FUNCTION a_upd_recording(); 39 | DROP FUNCTION a_upd_release(); 40 | DROP FUNCTION a_upd_release_event(); 41 | DROP FUNCTION a_upd_release_group(); 42 | DROP FUNCTION a_upd_release_group_primary_type_mirror(); 43 | DROP FUNCTION a_upd_release_group_secondary_type_mirror(); 44 | DROP FUNCTION a_upd_release_label(); 45 | DROP FUNCTION a_upd_track(); 46 | DROP FUNCTION apply_artist_release_group_pending_updates(); 47 | DROP FUNCTION apply_artist_release_pending_updates(); 48 | DROP FUNCTION b_ins_edit_materialize_status(); 49 | DROP FUNCTION b_upd_artist_credit_name(); 50 | DROP FUNCTION b_upd_last_updated_table(); 51 | DROP FUNCTION b_upd_link(); 52 | DROP FUNCTION b_upd_link_attribute(); 53 | DROP FUNCTION b_upd_link_attribute_credit(); 54 | DROP FUNCTION b_upd_link_attribute_text_value(); 55 | DROP FUNCTION b_upd_recording(); 56 | DROP FUNCTION b_upd_release_group_secondary_type_join(); 57 | DROP FUNCTION check_editor_name(); 58 | DROP FUNCTION check_has_dates(); 59 | DROP FUNCTION controlled_for_whitespace(TEXT); 60 | DROP FUNCTION create_bounding_cube(durations INTEGER[], fuzzy INTEGER); 61 | DROP FUNCTION create_cube_from_durations(durations INTEGER[]); 62 | DROP FUNCTION dec_nullable_artist_credit(row_id integer); 63 | DROP FUNCTION dec_ref_count(tbl varchar, row_id integer, val integer); 64 | DROP FUNCTION del_collection_sub_on_delete(); 65 | DROP FUNCTION del_collection_sub_on_private(); 66 | DROP FUNCTION delete_orphaned_recordings(); 67 | DROP FUNCTION delete_ratings(enttype TEXT, ids INTEGER[]); 68 | DROP FUNCTION delete_unused_aggregate_tag(entity_type taggable_entity_type, entity_id INTEGER, tag_id INTEGER); 69 | DROP FUNCTION delete_unused_tag(tag_id INT); 70 | DROP FUNCTION delete_unused_url(ids INTEGER[]); 71 | DROP FUNCTION deny_deprecated_links(); 72 | DROP FUNCTION deny_special_purpose_deletion(); 73 | DROP FUNCTION edit_data_type_info(data JSONB); 74 | DROP FUNCTION end_area_implies_ended(); 75 | DROP FUNCTION end_date_implies_ended(); 76 | DROP FUNCTION ensure_area_attribute_type_allows_text(); 77 | DROP FUNCTION ensure_artist_attribute_type_allows_text(); 78 | DROP FUNCTION ensure_event_attribute_type_allows_text(); 79 | DROP FUNCTION ensure_instrument_attribute_type_allows_text(); 80 | DROP FUNCTION ensure_label_attribute_type_allows_text(); 81 | DROP FUNCTION ensure_medium_attribute_type_allows_text(); 82 | DROP FUNCTION ensure_place_attribute_type_allows_text(); 83 | DROP FUNCTION ensure_recording_attribute_type_allows_text(); 84 | DROP FUNCTION ensure_release_attribute_type_allows_text(); 85 | DROP FUNCTION ensure_release_group_attribute_type_allows_text(); 86 | DROP FUNCTION ensure_series_attribute_type_allows_text(); 87 | DROP FUNCTION ensure_work_attribute_type_allows_text(); 88 | DROP FUNCTION from_hex(t text); 89 | DROP FUNCTION generate_uuid_v3(namespace varchar, name varchar); 90 | DROP FUNCTION generate_uuid_v4(); 91 | DROP FUNCTION get_recording_first_release_date_rows(condition TEXT); 92 | DROP FUNCTION get_release_first_release_date_rows(condition TEXT); 93 | DROP FUNCTION inc_nullable_artist_credit(row_id integer); 94 | DROP FUNCTION inc_ref_count(tbl varchar, row_id integer, val integer); 95 | DROP FUNCTION inserting_edits_requires_confirmed_email_address(); 96 | DROP FUNCTION integer_date(year SMALLINT, month SMALLINT, day SMALLINT); 97 | DROP FUNCTION materialise_recording_length(recording_id INT); 98 | DROP FUNCTION mb_lower(input text); 99 | DROP FUNCTION mb_simple_tsvector(input text); 100 | DROP FUNCTION median_track_length(recording_id integer); 101 | DROP FUNCTION padded_by_whitespace(TEXT); 102 | DROP FUNCTION prevent_invalid_attributes(); 103 | DROP FUNCTION remove_unused_links(); 104 | DROP FUNCTION remove_unused_url(); 105 | DROP FUNCTION replace_old_sub_on_add(); 106 | DROP FUNCTION restore_collection_sub_on_public(); 107 | DROP FUNCTION set_recordings_first_release_dates(recording_ids INTEGER[]); 108 | DROP FUNCTION set_release_first_release_date(release_id INTEGER); 109 | DROP FUNCTION set_release_group_first_release_date(release_group_id INTEGER); 110 | DROP FUNCTION set_releases_recordings_first_release_dates(release_ids INTEGER[]); 111 | DROP FUNCTION simplify_search_hints(); 112 | DROP FUNCTION track_count_matches_cdtoc(medium, int); 113 | DROP FUNCTION trg_delete_unused_tag(); 114 | DROP FUNCTION trg_delete_unused_tag_ref(); 115 | DROP FUNCTION update_aggregate_rating(entity_type ratable_entity_type, entity_id INTEGER); 116 | DROP FUNCTION update_aggregate_rating_for_raw_delete(); 117 | DROP FUNCTION update_aggregate_rating_for_raw_insert(); 118 | DROP FUNCTION update_aggregate_rating_for_raw_update(); 119 | DROP FUNCTION update_aggregate_tag_count(entity_type taggable_entity_type, entity_id INTEGER, tag_id INTEGER, count_change SMALLINT); 120 | DROP FUNCTION update_tag_counts_for_raw_delete(); 121 | DROP FUNCTION update_tag_counts_for_raw_insert(); 122 | DROP FUNCTION update_tag_counts_for_raw_update(); 123 | -------------------------------------------------------------------------------- /mbdata/sql/DropMirrorOnlyFunctions.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | DROP FUNCTION a_del_release_event_mirror(); 5 | DROP FUNCTION a_del_release_group_mirror(); 6 | DROP FUNCTION a_del_release_group_secondary_type_join_mirror(); 7 | DROP FUNCTION a_del_release_label_mirror(); 8 | DROP FUNCTION a_del_release_mirror(); 9 | DROP FUNCTION a_del_track_mirror(); 10 | DROP FUNCTION a_ins_release_event_mirror(); 11 | DROP FUNCTION a_ins_release_group_mirror(); 12 | DROP FUNCTION a_ins_release_group_secondary_type_join_mirror(); 13 | DROP FUNCTION a_ins_release_label_mirror(); 14 | DROP FUNCTION a_ins_release_mirror(); 15 | DROP FUNCTION a_ins_track_mirror(); 16 | DROP FUNCTION a_upd_release_event_mirror(); 17 | DROP FUNCTION a_upd_release_group_meta_mirror(); 18 | DROP FUNCTION a_upd_release_group_mirror(); 19 | DROP FUNCTION a_upd_release_label_mirror(); 20 | DROP FUNCTION a_upd_release_mirror(); 21 | DROP FUNCTION a_upd_track_mirror(); 22 | -------------------------------------------------------------------------------- /mbdata/sql/DropMirrorOnlyTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | DROP TRIGGER IF EXISTS a_ins_l_area_area_mirror ON l_area_area; 5 | DROP TRIGGER IF EXISTS a_upd_l_area_area_mirror ON l_area_area; 6 | DROP TRIGGER IF EXISTS a_del_l_area_area_mirror ON l_area_area; 7 | DROP TRIGGER IF EXISTS a_ins_release_mirror ON release; 8 | DROP TRIGGER IF EXISTS a_upd_release_mirror ON release; 9 | DROP TRIGGER IF EXISTS a_del_release_mirror ON release; 10 | DROP TRIGGER IF EXISTS a_ins_release_event_mirror ON release_country; 11 | DROP TRIGGER IF EXISTS a_upd_release_event_mirror ON release_country; 12 | DROP TRIGGER IF EXISTS a_del_release_event_mirror ON release_country; 13 | DROP TRIGGER IF EXISTS a_ins_release_event_mirror ON release_unknown_country; 14 | DROP TRIGGER IF EXISTS a_upd_release_event_mirror ON release_unknown_country; 15 | DROP TRIGGER IF EXISTS a_del_release_event_mirror ON release_unknown_country; 16 | DROP TRIGGER IF EXISTS a_ins_release_group_mirror ON release_group; 17 | DROP TRIGGER IF EXISTS a_upd_release_group_mirror ON release_group; 18 | DROP TRIGGER IF EXISTS a_del_release_group_mirror ON release_group; 19 | DROP TRIGGER IF EXISTS a_upd_release_group_meta_mirror ON release_group_meta; 20 | DROP TRIGGER IF EXISTS a_upd_release_group_primary_type_mirror ON release_group_primary_type; 21 | DROP TRIGGER IF EXISTS a_upd_release_group_secondary_type_mirror ON release_group_secondary_type; 22 | DROP TRIGGER IF EXISTS a_ins_release_group_secondary_type_join_mirror ON release_group_secondary_type_join; 23 | DROP TRIGGER IF EXISTS a_del_release_group_secondary_type_join_mirror ON release_group_secondary_type_join; 24 | DROP TRIGGER IF EXISTS a_ins_release_label_mirror ON release_label; 25 | DROP TRIGGER IF EXISTS a_upd_release_label_mirror ON release_label; 26 | DROP TRIGGER IF EXISTS a_del_release_label_mirror ON release_label; 27 | DROP TRIGGER IF EXISTS a_ins_track_mirror ON track; 28 | DROP TRIGGER IF EXISTS a_upd_track_mirror ON track; 29 | DROP TRIGGER IF EXISTS a_del_track_mirror ON track; 30 | DROP TRIGGER IF EXISTS apply_artist_release_group_pending_updates_mirror ON release; 31 | DROP TRIGGER IF EXISTS apply_artist_release_pending_updates_mirror ON release; 32 | DROP TRIGGER IF EXISTS apply_artist_release_pending_updates_mirror ON release_country; 33 | DROP TRIGGER IF EXISTS apply_artist_release_pending_updates_mirror ON release_first_release_date; 34 | DROP TRIGGER IF EXISTS apply_artist_release_group_pending_updates_mirror ON release_group; 35 | DROP TRIGGER IF EXISTS apply_artist_release_group_pending_updates_mirror ON release_group_meta; 36 | DROP TRIGGER IF EXISTS apply_artist_release_group_pending_updates_mirror ON release_group_primary_type; 37 | DROP TRIGGER IF EXISTS apply_artist_release_group_pending_updates_mirror ON release_group_secondary_type; 38 | DROP TRIGGER IF EXISTS apply_artist_release_group_pending_updates_mirror ON release_group_secondary_type_join; 39 | DROP TRIGGER IF EXISTS apply_artist_release_pending_updates_mirror ON release_label; 40 | DROP TRIGGER IF EXISTS apply_artist_release_group_pending_updates_mirror ON track; 41 | DROP TRIGGER IF EXISTS apply_artist_release_pending_updates_mirror ON track; 42 | -------------------------------------------------------------------------------- /mbdata/sql/DropSearchIndexes.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | DROP INDEX area_alias_idx_txt; 5 | DROP INDEX area_alias_idx_txt_sort; 6 | DROP INDEX area_idx_name_txt; 7 | DROP INDEX artist_alias_idx_txt; 8 | DROP INDEX artist_alias_idx_txt_sort; 9 | DROP INDEX artist_credit_idx_txt; 10 | DROP INDEX artist_credit_name_idx_txt; 11 | DROP INDEX artist_idx_txt; 12 | DROP INDEX artist_idx_txt_sort; 13 | DROP INDEX event_alias_idx_txt; 14 | DROP INDEX event_alias_idx_txt_sort; 15 | DROP INDEX event_idx_txt; 16 | DROP INDEX instrument_idx_txt; 17 | DROP INDEX label_alias_idx_txt; 18 | DROP INDEX label_alias_idx_txt_sort; 19 | DROP INDEX label_idx_txt; 20 | DROP INDEX place_alias_idx_txt; 21 | DROP INDEX place_alias_idx_txt_sort; 22 | DROP INDEX place_idx_name_txt; 23 | DROP INDEX recording_alias_idx_txt; 24 | DROP INDEX recording_alias_idx_txt_sort; 25 | DROP INDEX recording_idx_txt; 26 | DROP INDEX release_alias_idx_txt; 27 | DROP INDEX release_alias_idx_txt_sort; 28 | DROP INDEX release_group_alias_idx_txt; 29 | DROP INDEX release_group_alias_idx_txt_sort; 30 | DROP INDEX release_group_idx_txt; 31 | DROP INDEX release_idx_txt; 32 | DROP INDEX series_alias_idx_txt; 33 | DROP INDEX series_alias_idx_txt_sort; 34 | DROP INDEX series_idx_txt; 35 | DROP INDEX tag_idx_name_txt; 36 | DROP INDEX work_alias_idx_txt; 37 | DROP INDEX work_alias_idx_txt_sort; 38 | DROP INDEX work_idx_txt; 39 | -------------------------------------------------------------------------------- /mbdata/sql/DropTypes.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | DROP TYPE IF EXISTS cover_art_presence; 5 | DROP TYPE IF EXISTS edit_note_status; 6 | DROP TYPE IF EXISTS event_art_presence; 7 | DROP TYPE IF EXISTS fluency; 8 | DROP TYPE IF EXISTS oauth_code_challenge_method; 9 | DROP TYPE IF EXISTS ratable_entity_type; 10 | DROP TYPE IF EXISTS taggable_entity_type; 11 | -------------------------------------------------------------------------------- /mbdata/sql/DropViews.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | DROP VIEW artist_series; 5 | DROP VIEW event_series; 6 | DROP VIEW medium_track_durations; 7 | DROP VIEW recording_series; 8 | DROP VIEW release_event; 9 | DROP VIEW release_group_series; 10 | DROP VIEW release_series; 11 | DROP VIEW work_series; 12 | -------------------------------------------------------------------------------- /mbdata/sql/EnableLastUpdatedTriggers.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | DO $$ 6 | DECLARE 7 | r record; 8 | BEGIN 9 | FOR r IN ( 10 | SELECT * 11 | FROM information_schema.triggers 12 | WHERE action_statement LIKE '%b_upd_last_updated_table%' 13 | ) LOOP 14 | EXECUTE 'ALTER TABLE ' || 15 | quote_ident(r.event_object_schema) || '.' || 16 | quote_ident(r.event_object_table) || 17 | ' ENABLE TRIGGER ' || 18 | quote_ident(r.trigger_name); 19 | END LOOP; 20 | END $$; 21 | 22 | COMMIT; 23 | -------------------------------------------------------------------------------- /mbdata/sql/Extensions.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | BEGIN; 3 | 4 | CREATE EXTENSION IF NOT EXISTS cube WITH SCHEMA public; 5 | CREATE EXTENSION IF NOT EXISTS earthdistance WITH SCHEMA public; 6 | CREATE EXTENSION IF NOT EXISTS unaccent WITH SCHEMA public; 7 | 8 | -- Substitute public.ll_to_earth for a version that schema-qualifies 9 | -- references to public.cube and public.earth, to avoid errors during 10 | -- inlining/execution of the function while running an autovacuum or 11 | -- pg_upgrade. 12 | -- 13 | -- The issue in question arises since postgres 10.3: a change was made to 14 | -- only include pg_catalog in the search_path settings of postgres client 15 | -- programs in order to resolve a security issue. So, since `cube` and 16 | -- `earth` are installed in the public schema, they're invisible in these 17 | -- contexts without the qualification. 18 | 19 | CREATE OR REPLACE FUNCTION musicbrainz.ll_to_earth(float8, float8) 20 | RETURNS public.earth 21 | LANGUAGE SQL 22 | IMMUTABLE STRICT 23 | PARALLEL SAFE 24 | AS 'SELECT public.cube(public.cube(public.cube(public.earth()*cos(radians($1))*cos(radians($2))),public.earth()*cos(radians($1))*sin(radians($2))),public.earth()*sin(radians($1)))::public.earth'; 25 | 26 | -- The unaccent function, but IMMUTABLE. Based on a solution provided by 27 | -- Erwin Brandstetter in [1], which removes the dependency on search_path. 28 | -- Warning: changing the unaccent dictionary on the filesystem can still 29 | -- break the IMMUTABLE assumption. 30 | -- 31 | -- The answer in [1] suggests that using a C function for immutable_unaccent 32 | -- allows it to be inlined in musicbrainz_unaccent below, and is 10x faster 33 | -- than the fallback. Although this script is meant to execute as a 34 | -- superuser, a fallback is provided specifically for instances where even 35 | -- the "superuser" is restricted in creating C language functions, e.g. 36 | -- Amazon RDS. 37 | -- 38 | -- [1] https://stackoverflow.com/a/11007216 39 | 40 | DO $$ 41 | BEGIN 42 | CREATE OR REPLACE FUNCTION public.immutable_unaccent(regdictionary, text) 43 | RETURNS text LANGUAGE c IMMUTABLE PARALLEL SAFE STRICT AS 44 | '$libdir/unaccent', 'unaccent_dict'; 45 | 46 | CREATE OR REPLACE FUNCTION musicbrainz.musicbrainz_unaccent(text) 47 | RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS 48 | $func$ 49 | SELECT public.immutable_unaccent(regdictionary 'public.unaccent', $1) 50 | $func$; 51 | EXCEPTION 52 | WHEN insufficient_privilege THEN 53 | CREATE OR REPLACE FUNCTION musicbrainz.musicbrainz_unaccent(text) 54 | RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS 55 | $func$ 56 | SELECT public.unaccent('public.unaccent', $1) 57 | $func$; 58 | END 59 | $$; 60 | 61 | COMMIT; 62 | -- vi: set ts=4 sw=4 et : 63 | -------------------------------------------------------------------------------- /mbdata/sql/InsertDefaultRows.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | INSERT INTO artist (name, sort_name, gid) VALUES 6 | ('Various Artists', 'Various Artists', '89ad4ac3-39f7-470e-963a-56509c546377'), 7 | ('Deleted Artist', 'Deleted Artist', 'c06aa285-520e-40c0-b776-83d2c9e8a6d1'); 8 | 9 | INSERT INTO label (name, gid) VALUES 10 | ('Deleted Label', 'f43e252d-9ebf-4e8e-bba8-36d080756cc1'); 11 | 12 | INSERT INTO editor (id, name, password, ha1) VALUES (1, 'Anonymous', '', ''); 13 | INSERT INTO editor (id, name, password, ha1) VALUES (2, 'FreeDB', '', ''); 14 | INSERT INTO editor (id, name, password, ha1) VALUES (4, 'ModBot', '', ''); 15 | 16 | INSERT INTO replication_control VALUES ( 17 | 1, -- fixed primary key 18 | 1, -- schema #1 19 | NULL,-- until we pull in a particular dump, we don't know what replication sequence we're at 20 | NULL 21 | ); 22 | 23 | INSERT INTO release_group_primary_type VALUES (1, 'Album', null, 1, null, 'f529b476-6e62-324f-b0aa-1f3e33d313fc'); 24 | INSERT INTO release_group_primary_type VALUES (2, 'Single', null, 2, null, 'd6038452-8ee0-3f68-affc-2de9a1ede0b9'); 25 | 26 | INSERT INTO release_status VALUES (1, 'Official', null, 1, null, '4e304316-386d-3409-af2e-78857eec5cfe'); 27 | 28 | COMMIT; 29 | 30 | -- vi: set ts=4 sw=4 et : 31 | -------------------------------------------------------------------------------- /mbdata/sql/ReplicationSetup.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | SET search_path = musicbrainz; 3 | 4 | BEGIN; 5 | 6 | -- To "install" the pending.so function, execute this as user postgres 7 | -- Normally this is done by InitDb.pl so you don't really have to worry about it. 8 | --CREATE FUNCTION "recordchange" () RETURNS trigger AS 9 | --'$libdir/pending', 'recordchange' LANGUAGE C; 10 | 11 | CREATE AGGREGATE array_cat_agg(int2[]) ( 12 | sfunc = array_cat, 13 | stype = int2[], 14 | initcond = '{}' 15 | ); 16 | 17 | CREATE TABLE dbmirror_Pending ( 18 | SeqId serial, 19 | TableName varchar NOT NULL, 20 | Op character, 21 | XID int4 NOT NULL, 22 | PRIMARY KEY (SeqId) 23 | ); 24 | 25 | CREATE INDEX dbmirror_Pending_XID_Index ON dbmirror_Pending (XID); 26 | 27 | CREATE TABLE dbmirror_PendingData ( 28 | SeqId int4 NOT NULL, 29 | IsKey bool NOT NULL, 30 | Data varchar, 31 | PRIMARY KEY (SeqId, IsKey) , 32 | FOREIGN KEY (SeqId) REFERENCES dbmirror_Pending (SeqId) ON UPDATE CASCADE ON DELETE CASCADE 33 | ); 34 | 35 | COMMIT; 36 | 37 | -- vi: set ts=4 sw=4 et : 38 | -------------------------------------------------------------------------------- /mbdata/sql/caa/CreateEditFKConstraints.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | SET search_path = 'cover_art_archive'; 4 | 5 | ALTER TABLE cover_art 6 | ADD CONSTRAINT cover_art_fk_edit 7 | FOREIGN KEY (edit) 8 | REFERENCES musicbrainz.edit(id); 9 | -------------------------------------------------------------------------------- /mbdata/sql/caa/CreateFKConstraints.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | ALTER TABLE art_type 7 | ADD CONSTRAINT art_type_fk_parent 8 | FOREIGN KEY (parent) 9 | REFERENCES cover_art_archive.art_type(id); 10 | 11 | ALTER TABLE cover_art 12 | ADD CONSTRAINT cover_art_fk_release 13 | FOREIGN KEY (release) 14 | REFERENCES musicbrainz.release(id) 15 | ON DELETE CASCADE; 16 | 17 | ALTER TABLE cover_art 18 | ADD CONSTRAINT cover_art_fk_mime_type 19 | FOREIGN KEY (mime_type) 20 | REFERENCES cover_art_archive.image_type(mime_type); 21 | 22 | ALTER TABLE cover_art_type 23 | ADD CONSTRAINT cover_art_type_fk_id 24 | FOREIGN KEY (id) 25 | REFERENCES cover_art_archive.cover_art(id) 26 | ON DELETE CASCADE; 27 | 28 | ALTER TABLE cover_art_type 29 | ADD CONSTRAINT cover_art_type_fk_type_id 30 | FOREIGN KEY (type_id) 31 | REFERENCES cover_art_archive.art_type(id); 32 | 33 | ALTER TABLE release_group_cover_art 34 | ADD CONSTRAINT release_group_cover_art_fk_release_group 35 | FOREIGN KEY (release_group) 36 | REFERENCES musicbrainz.release_group(id); 37 | 38 | ALTER TABLE release_group_cover_art 39 | ADD CONSTRAINT release_group_cover_art_fk_release 40 | FOREIGN KEY (release) 41 | REFERENCES musicbrainz.release(id); 42 | 43 | -------------------------------------------------------------------------------- /mbdata/sql/caa/CreateFunctions.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | SET search_path = 'cover_art_archive'; 4 | 5 | CREATE OR REPLACE FUNCTION materialize_caa_presence() RETURNS trigger AS $$ 6 | BEGIN 7 | -- On delete, set the presence flag to 'absent' if there's no more 8 | -- cover art 9 | IF TG_OP = 'DELETE' THEN 10 | IF NOT EXISTS ( 11 | SELECT TRUE FROM cover_art_archive.cover_art 12 | WHERE release = OLD.release 13 | ) THEN 14 | UPDATE musicbrainz.release_meta 15 | SET cover_art_presence = 'absent' 16 | WHERE id = OLD.release; 17 | END IF; 18 | END IF; 19 | 20 | -- On insert, set the presence flag to 'present' if it was previously 21 | -- 'absent' 22 | IF TG_OP = 'INSERT' THEN 23 | CASE ( 24 | SELECT cover_art_presence FROM musicbrainz.release_meta 25 | WHERE id = NEW.release 26 | ) 27 | WHEN 'absent' THEN 28 | UPDATE musicbrainz.release_meta 29 | SET cover_art_presence = 'present' 30 | WHERE id = NEW.release; 31 | WHEN 'darkened' THEN 32 | RAISE EXCEPTION 'This release has been darkened and cannot have new cover art'; 33 | ELSE 34 | END CASE; 35 | END IF; 36 | 37 | RETURN NULL; 38 | END; 39 | $$ LANGUAGE 'plpgsql'; 40 | 41 | CREATE OR REPLACE FUNCTION resequence_positions(release_id INT) RETURNS void AS $$ 42 | BEGIN 43 | UPDATE cover_art_archive.cover_art 44 | SET ordering = recalculated.row_number 45 | FROM ( 46 | SELECT *, 47 | row_number() OVER (PARTITION BY release ORDER BY ordering ASC) 48 | FROM cover_art_archive.cover_art 49 | WHERE cover_art.release = release_id 50 | ) recalculated 51 | WHERE recalculated.id = cover_art.id AND 52 | recalculated.row_number != cover_art.ordering; 53 | END; 54 | $$ LANGUAGE 'plpgsql'; 55 | 56 | CREATE OR REPLACE FUNCTION resequence_cover_art_trigger() RETURNS trigger AS $$ 57 | BEGIN 58 | IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN 59 | PERFORM cover_art_archive.resequence_positions(NEW.release); 60 | END IF; 61 | 62 | IF (TG_OP = 'DELETE') OR 63 | (TG_OP = 'UPDATE' AND NEW.release != OLD.release) 64 | THEN 65 | PERFORM cover_art_archive.resequence_positions(OLD.release); 66 | END IF; 67 | 68 | RETURN NULL; 69 | END; 70 | $$ LANGUAGE 'plpgsql'; 71 | 72 | COMMIT; 73 | -------------------------------------------------------------------------------- /mbdata/sql/caa/CreateIndexes.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | SET search_path = 'cover_art_archive'; 6 | 7 | CREATE INDEX cover_art_idx_release ON cover_art (release); 8 | CREATE UNIQUE INDEX art_type_idx_gid ON art_type (gid); 9 | 10 | COMMIT; 11 | -------------------------------------------------------------------------------- /mbdata/sql/caa/CreatePrimaryKeys.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | ALTER TABLE art_type ADD CONSTRAINT art_type_pkey PRIMARY KEY (id); 7 | ALTER TABLE cover_art ADD CONSTRAINT cover_art_pkey PRIMARY KEY (id); 8 | ALTER TABLE cover_art_type ADD CONSTRAINT cover_art_type_pkey PRIMARY KEY (id, type_id); 9 | ALTER TABLE image_type ADD CONSTRAINT image_type_pkey PRIMARY KEY (mime_type); 10 | ALTER TABLE release_group_cover_art ADD CONSTRAINT release_group_cover_art_pkey PRIMARY KEY (release_group); 11 | -------------------------------------------------------------------------------- /mbdata/sql/caa/CreateReplicationTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'cover_art_archive', musicbrainz, public; 5 | 6 | BEGIN; 7 | 8 | CREATE TRIGGER "reptg_art_type" 9 | AFTER INSERT OR DELETE OR UPDATE ON "art_type" 10 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" ('verbose'); 11 | 12 | CREATE TRIGGER "reptg_cover_art" 13 | AFTER INSERT OR DELETE OR UPDATE ON "cover_art" 14 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" ('verbose'); 15 | 16 | CREATE TRIGGER "reptg_cover_art_type" 17 | AFTER INSERT OR DELETE OR UPDATE ON "cover_art_type" 18 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" ('verbose'); 19 | 20 | CREATE TRIGGER "reptg_image_type" 21 | AFTER INSERT OR DELETE OR UPDATE ON "image_type" 22 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" ('verbose'); 23 | 24 | CREATE TRIGGER "reptg_release_group_cover_art" 25 | AFTER INSERT OR DELETE OR UPDATE ON "release_group_cover_art" 26 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" ('verbose'); 27 | 28 | COMMIT; 29 | -------------------------------------------------------------------------------- /mbdata/sql/caa/CreateReplicationTriggers2.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'cover_art_archive', musicbrainz, public; 5 | 6 | BEGIN; 7 | 8 | CREATE TRIGGER reptg2_art_type 9 | AFTER INSERT OR DELETE OR UPDATE ON art_type 10 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 11 | 12 | CREATE TRIGGER reptg2_cover_art 13 | AFTER INSERT OR DELETE OR UPDATE ON cover_art 14 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 15 | 16 | CREATE TRIGGER reptg2_cover_art_type 17 | AFTER INSERT OR DELETE OR UPDATE ON cover_art_type 18 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 19 | 20 | CREATE TRIGGER reptg2_image_type 21 | AFTER INSERT OR DELETE OR UPDATE ON image_type 22 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 23 | 24 | CREATE TRIGGER reptg2_release_group_cover_art 25 | AFTER INSERT OR DELETE OR UPDATE ON release_group_cover_art 26 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 27 | 28 | COMMIT; 29 | -------------------------------------------------------------------------------- /mbdata/sql/caa/CreateTables.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | SET search_path = 'cover_art_archive'; 6 | 7 | CREATE TABLE art_type ( -- replicate (verbose) 8 | id SERIAL NOT NULL, -- PK 9 | name TEXT NOT NULL, 10 | parent INTEGER, -- references cover_art_archive.art_type.id 11 | child_order INTEGER NOT NULL DEFAULT 0, 12 | description TEXT, 13 | gid uuid NOT NULL 14 | ); 15 | 16 | CREATE TABLE image_type ( -- replicate (verbose) 17 | mime_type TEXT NOT NULL, -- PK 18 | suffix TEXT NOT NULL 19 | ); 20 | 21 | CREATE TABLE cover_art ( -- replicate (verbose) 22 | id BIGINT NOT NULL, -- PK 23 | release INTEGER NOT NULL, -- references musicbrainz.release.id CASCADE 24 | comment TEXT NOT NULL DEFAULT '', 25 | edit INTEGER NOT NULL, -- separately references musicbrainz.edit.id 26 | ordering INTEGER NOT NULL CHECK (ordering > 0), 27 | date_uploaded TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, 28 | edits_pending INTEGER NOT NULL DEFAULT 0 CHECK (edits_pending >= 0), 29 | mime_type TEXT NOT NULL, -- references cover_art_archive.image_type.mime_type 30 | filesize INTEGER, 31 | thumb_250_filesize INTEGER, 32 | thumb_500_filesize INTEGER, 33 | thumb_1200_filesize INTEGER 34 | ); 35 | 36 | CREATE TABLE cover_art_type ( -- replicate (verbose) 37 | id BIGINT NOT NULL, -- PK, references cover_art_archive.cover_art.id CASCADE, 38 | type_id INTEGER NOT NULL -- PK, references cover_art_archive.art_type.id, 39 | ); 40 | 41 | CREATE TABLE release_group_cover_art ( -- replicate (verbose) 42 | release_group INTEGER NOT NULL, -- PK, references musicbrainz.release_group.id 43 | release INTEGER NOT NULL -- FK, references musicbrainz.release.id 44 | ); 45 | 46 | COMMIT; 47 | -------------------------------------------------------------------------------- /mbdata/sql/caa/CreateTriggers.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | SET search_path = 'cover_art_archive'; 4 | 5 | CREATE TRIGGER update_release_coverart AFTER INSERT OR DELETE 6 | ON cover_art_archive.cover_art 7 | FOR EACH ROW EXECUTE PROCEDURE materialize_caa_presence(); 8 | 9 | CREATE CONSTRAINT TRIGGER resquence_cover_art AFTER INSERT OR UPDATE OR DELETE 10 | ON cover_art_archive.cover_art DEFERRABLE INITIALLY DEFERRED 11 | FOR EACH ROW EXECUTE PROCEDURE resequence_cover_art_trigger(); 12 | 13 | COMMIT; 14 | -------------------------------------------------------------------------------- /mbdata/sql/caa/CreateViews.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | SET search_path = 'cover_art_archive'; 6 | 7 | CREATE OR REPLACE VIEW index_listing AS 8 | SELECT cover_art.*, 9 | (edit.close_time IS NOT NULL) AS approved, 10 | coalesce(cover_art.id = (SELECT id FROM cover_art_archive.cover_art_type 11 | JOIN cover_art_archive.cover_art ca_front USING (id) 12 | WHERE ca_front.release = cover_art.release 13 | AND type_id = 1 14 | ORDER BY ca_front.ordering 15 | LIMIT 1), FALSE) AS is_front, 16 | coalesce(cover_art.id = (SELECT id FROM cover_art_archive.cover_art_type 17 | JOIN cover_art_archive.cover_art ca_front USING (id) 18 | WHERE ca_front.release = cover_art.release 19 | AND type_id = 2 20 | ORDER BY ca_front.ordering 21 | LIMIT 1), FALSE) AS is_back, 22 | array(SELECT art_type.name 23 | FROM cover_art_archive.cover_art_type 24 | JOIN cover_art_archive.art_type ON cover_art_type.type_id = art_type.id 25 | WHERE cover_art_type.id = cover_art.id) AS types 26 | FROM cover_art_archive.cover_art 27 | LEFT JOIN musicbrainz.edit ON edit.id = cover_art.edit; 28 | 29 | COMMIT; 30 | -------------------------------------------------------------------------------- /mbdata/sql/caa/DropFKConstraints.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | ALTER TABLE art_type DROP CONSTRAINT IF EXISTS art_type_fk_parent; 7 | ALTER TABLE cover_art DROP CONSTRAINT IF EXISTS cover_art_fk_release; 8 | ALTER TABLE cover_art DROP CONSTRAINT IF EXISTS cover_art_fk_edit; 9 | ALTER TABLE cover_art DROP CONSTRAINT IF EXISTS cover_art_fk_mime_type; 10 | ALTER TABLE cover_art_type DROP CONSTRAINT IF EXISTS cover_art_type_fk_id; 11 | ALTER TABLE cover_art_type DROP CONSTRAINT IF EXISTS cover_art_type_fk_type_id; 12 | ALTER TABLE release_group_cover_art DROP CONSTRAINT IF EXISTS release_group_cover_art_fk_release_group; 13 | ALTER TABLE release_group_cover_art DROP CONSTRAINT IF EXISTS release_group_cover_art_fk_release; 14 | -------------------------------------------------------------------------------- /mbdata/sql/caa/DropFunctions.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | DROP FUNCTION materialize_caa_presence(); 7 | DROP FUNCTION resequence_cover_art_trigger(); 8 | DROP FUNCTION resequence_positions(release_id INT); 9 | -------------------------------------------------------------------------------- /mbdata/sql/caa/DropIndexes.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | DROP INDEX art_type_idx_gid; 7 | DROP INDEX cover_art_idx_release; 8 | -------------------------------------------------------------------------------- /mbdata/sql/caa/DropPrimaryKeys.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | ALTER TABLE art_type DROP CONSTRAINT IF EXISTS art_type_pkey; 7 | ALTER TABLE cover_art DROP CONSTRAINT IF EXISTS cover_art_pkey; 8 | ALTER TABLE cover_art_type DROP CONSTRAINT IF EXISTS cover_art_type_pkey; 9 | ALTER TABLE image_type DROP CONSTRAINT IF EXISTS image_type_pkey; 10 | ALTER TABLE release_group_cover_art DROP CONSTRAINT IF EXISTS release_group_cover_art_pkey; 11 | -------------------------------------------------------------------------------- /mbdata/sql/caa/DropReplicationTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | DROP TRIGGER IF EXISTS reptg_art_type ON art_type; 7 | DROP TRIGGER IF EXISTS reptg_cover_art ON cover_art; 8 | DROP TRIGGER IF EXISTS reptg_cover_art_type ON cover_art_type; 9 | DROP TRIGGER IF EXISTS reptg_image_type ON image_type; 10 | DROP TRIGGER IF EXISTS reptg_release_group_cover_art ON release_group_cover_art; 11 | -------------------------------------------------------------------------------- /mbdata/sql/caa/DropReplicationTriggers2.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | DROP TRIGGER IF EXISTS reptg2_art_type ON art_type; 7 | DROP TRIGGER IF EXISTS reptg2_cover_art ON cover_art; 8 | DROP TRIGGER IF EXISTS reptg2_cover_art_type ON cover_art_type; 9 | DROP TRIGGER IF EXISTS reptg2_image_type ON image_type; 10 | DROP TRIGGER IF EXISTS reptg2_release_group_cover_art ON release_group_cover_art; 11 | -------------------------------------------------------------------------------- /mbdata/sql/caa/DropTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | DROP TABLE art_type; 7 | DROP TABLE cover_art; 8 | DROP TABLE cover_art_type; 9 | DROP TABLE image_type; 10 | DROP TABLE release_group_cover_art; 11 | -------------------------------------------------------------------------------- /mbdata/sql/caa/DropTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | DROP TRIGGER IF EXISTS update_release_coverart ON cover_art_archive.cover_art; 7 | DROP TRIGGER IF EXISTS resquence_cover_art ON cover_art_archive.cover_art; 8 | -------------------------------------------------------------------------------- /mbdata/sql/caa/DropViews.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | DROP VIEW index_listing; 7 | -------------------------------------------------------------------------------- /mbdata/sql/caa/SetSequences.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | SELECT setval('art_type_id_seq', COALESCE((SELECT MAX(id) FROM art_type), 0) + 1, FALSE); 7 | -------------------------------------------------------------------------------- /mbdata/sql/caa/TruncateTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'cover_art_archive'; 5 | 6 | TRUNCATE TABLE art_type RESTART IDENTITY CASCADE; 7 | TRUNCATE TABLE cover_art RESTART IDENTITY CASCADE; 8 | TRUNCATE TABLE cover_art_type RESTART IDENTITY CASCADE; 9 | TRUNCATE TABLE image_type RESTART IDENTITY CASCADE; 10 | TRUNCATE TABLE release_group_cover_art RESTART IDENTITY CASCADE; 11 | -------------------------------------------------------------------------------- /mbdata/sql/dbmirror2/MasterSetup.sql: -------------------------------------------------------------------------------- 1 | -- Copyright (C) 2021 MetaBrainz Foundation 2 | -- Licensed under the GPL version 2, or (at your option) any later version: 3 | -- http://www.gnu.org/licenses/gpl-2.0.txt 4 | 5 | BEGIN; 6 | 7 | -- The column_info view allows us to determine whether a column in a given 8 | -- table is part of its primary key, and gives us its position too. 9 | -- 10 | -- This view must be refreshed after every schema change; an event trigger 11 | -- in MasterEventTriggerSetup.sql can handle this automatically. 12 | CREATE MATERIALIZED VIEW dbmirror2.column_info ( 13 | table_schema, 14 | table_name, 15 | column_name, 16 | position, 17 | is_primary 18 | ) AS 19 | SELECT 20 | c.table_schema, 21 | c.table_name, 22 | c.column_name, 23 | c.ordinal_position, 24 | coalesce(( 25 | SELECT TRUE 26 | FROM information_schema.key_column_usage kcu 27 | NATURAL JOIN information_schema.table_constraints tc 28 | WHERE kcu.table_schema = c.table_schema 29 | AND kcu.table_name = c.table_name 30 | AND kcu.column_name = c.column_name 31 | AND tc.constraint_type = 'PRIMARY KEY' 32 | ), FALSE) AS is_primary 33 | FROM information_schema.columns c 34 | NATURAL JOIN information_schema.tables t 35 | WHERE t.table_type = 'BASE TABLE' 36 | AND t.table_schema NOT IN ('dbmirror2', 'information_schema', 'pg_catalog') 37 | WITH DATA; 38 | 39 | CREATE INDEX column_info_idx 40 | ON dbmirror2.column_info (table_schema, table_name, is_primary); 41 | 42 | CREATE FUNCTION dbmirror2.recordchange() 43 | RETURNS trigger AS $$ 44 | DECLARE 45 | -- prefixed with an underscore to disambiguate it from the column names 46 | -- pending_data.tablename and pending_keys.tablename 47 | _tablename TEXT; 48 | keys TEXT[]; 49 | jsonquery TEXT; 50 | olddata JSON; 51 | newdata JSON; 52 | -- prefixed with 'x' to avoid conflict with column name in queries 53 | xoldctid TID; 54 | nextseqid BIGINT; 55 | -- out-of-order seqid 56 | oooseqid BIGINT; 57 | oootrgdepth INTEGER; 58 | pdcursor NO SCROLL CURSOR (oooseqid INTEGER) FOR 59 | SELECT seqid 60 | FROM dbmirror2.pending_data 61 | WHERE xid = txid_current() 62 | AND seqid >= oooseqid 63 | ORDER BY seqid DESC 64 | FOR UPDATE; 65 | BEGIN 66 | _tablename := ( 67 | quote_ident(TG_TABLE_SCHEMA) || '.' || quote_ident(TG_TABLE_NAME) 68 | ); 69 | 70 | nextseqid := nextval( 71 | pg_get_serial_sequence('dbmirror2.pending_data', 'seqid') 72 | ); 73 | 74 | INSERT INTO dbmirror2.pending_ts (xid, ts) 75 | VALUES (txid_current(), transaction_timestamp()) 76 | ON CONFLICT DO NOTHING; 77 | 78 | jsonquery := ( 79 | SELECT format( 80 | 'SELECT json_build_object(%1$s)', 81 | array_to_string( 82 | array_agg( 83 | format('%1$L, ($1).%1$I', column_name) ORDER BY position 84 | ), 85 | ', ' 86 | ) 87 | ) 88 | FROM dbmirror2.column_info 89 | WHERE table_schema = TG_TABLE_SCHEMA AND table_name = TG_TABLE_NAME 90 | ); 91 | 92 | IF TG_OP != 'INSERT' THEN 93 | EXECUTE jsonquery INTO olddata USING OLD; 94 | 95 | xoldctid := OLD.ctid; 96 | END IF; 97 | 98 | IF TG_OP != 'DELETE' THEN 99 | EXECUTE jsonquery INTO newdata USING NEW; 100 | 101 | -- Detect out-of-order operations caused by cascading triggers. 102 | -- 103 | -- When row-level AFTER triggers are cascaded, the innermost trigger 104 | -- runs first. This means we may potentially see an UPDATE or DELETE 105 | -- of a row version that hasn't been added yet. 106 | -- 107 | -- We detect this by storing OLD.ctid for every operation. (The ctid 108 | -- is a tuple describing the physical location of the row version. We 109 | -- only need this to be stable for the lifetime of the current 110 | -- transaction.) We then check if there's a previous operation whose 111 | -- OLD ctid equals our NEW ctid; these are then known to be out-of- 112 | -- order. This previous operation's seqid is assigned to `oooseqid` 113 | -- ("out-of-order seqid"). 114 | -- 115 | -- The order is fixed by shifting the sequence IDs from the current 116 | -- transaction until they're corrected. The current-last operation 117 | -- assumes `nextseqid`, the second-to-last assumes the seqid of the 118 | -- last, and so on until `oooseqid` is unused. We then insert our new 119 | -- operation with `oooseqid`. 120 | -- 121 | -- Since we're never modifying `pending_data` rows inserted by other 122 | -- transactions, this shifting should be safe. 123 | SELECT seqid, trgdepth INTO oooseqid, oootrgdepth 124 | FROM dbmirror2.pending_data 125 | WHERE xid = txid_current() 126 | AND tablename = _tablename 127 | AND oldctid = NEW.ctid; 128 | 129 | IF FOUND THEN 130 | IF oootrgdepth IS NOT NULL AND oootrgdepth <= pg_trigger_depth() THEN 131 | -- This should never happen! Cascading triggers are the only 132 | -- known way for operations to arrive out of order. This 133 | -- warning must be investigated if it's ever logged. 134 | RAISE WARNING 'oootrgdepth (%) <= pg_trigger_depth() (%) (% ON %, OLD: %, NEW: %)', 135 | oootrgdepth, pg_trigger_depth(), TG_OP, _tablename, OLD, NEW; 136 | END IF; 137 | 138 | FOR pdrecord IN pdcursor (oooseqid := oooseqid) LOOP 139 | UPDATE dbmirror2.pending_data 140 | SET seqid = nextseqid 141 | WHERE CURRENT OF pdcursor; 142 | 143 | nextseqid := pdrecord.seqid; 144 | END LOOP; 145 | 146 | ASSERT (nextseqid = oooseqid); 147 | END IF; 148 | END IF; 149 | 150 | INSERT INTO dbmirror2.pending_data 151 | (seqid, tablename, op, xid, olddata, newdata, oldctid, trgdepth) 152 | VALUES ( 153 | nextseqid, 154 | _tablename, 155 | lower(left(TG_OP, 1)), 156 | txid_current(), 157 | olddata, 158 | newdata, 159 | xoldctid, 160 | pg_trigger_depth() 161 | ); 162 | 163 | RETURN NULL; 164 | END; 165 | $$ LANGUAGE plpgsql; 166 | 167 | COMMIT; 168 | -------------------------------------------------------------------------------- /mbdata/sql/dbmirror2/README: -------------------------------------------------------------------------------- 1 | ReplicationSetup.sql and MasterSetup.sql are copied from 2 | https://github.com/metabrainz/dbmirror2, commit eda9923. (These are the only 3 | two files we need, and submodules are "difficult.") 4 | 5 | This is not a fork; please do not make any changes to the files here without 6 | first submitting them upstream to dbmirror2. They should exactly mirror the 7 | commit mentioned in the first paragraph. 8 | -------------------------------------------------------------------------------- /mbdata/sql/dbmirror2/RefreshColumnInfo.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | DO $$ 6 | BEGIN 7 | PERFORM 1 FROM pg_matviews 8 | WHERE schemaname = 'dbmirror2' 9 | AND matviewname = 'column_info'; 10 | 11 | IF FOUND THEN 12 | REFRESH MATERIALIZED VIEW dbmirror2.column_info; 13 | END IF; 14 | END $$; 15 | 16 | COMMIT; 17 | -------------------------------------------------------------------------------- /mbdata/sql/dbmirror2/ReplicationSetup.sql: -------------------------------------------------------------------------------- 1 | -- Copyright (C) 2021 MetaBrainz Foundation 2 | -- Licensed under the GPL version 2, or (at your option) any later version: 3 | -- http://www.gnu.org/licenses/gpl-2.0.txt 4 | 5 | BEGIN; 6 | 7 | -- The pending_keys tables serves two purposes: 8 | -- 1. Stores the primary keys associated with each table. 9 | -- 2. Allows quickly checking if a particular table has changed 10 | -- in the packet. 11 | CREATE TABLE dbmirror2.pending_keys ( 12 | tablename TEXT, 13 | keys TEXT[] NOT NULL 14 | ); 15 | 16 | ALTER TABLE dbmirror2.pending_keys 17 | ADD CONSTRAINT pending_keys_pkey 18 | PRIMARY KEY (tablename); 19 | 20 | CREATE TABLE dbmirror2.pending_ts ( 21 | xid BIGINT, 22 | ts TIMESTAMP WITH TIME ZONE NOT NULL 23 | ); 24 | 25 | ALTER TABLE dbmirror2.pending_ts 26 | ADD CONSTRAINT pending_ts_pkey 27 | PRIMARY KEY (xid); 28 | 29 | CREATE TABLE dbmirror2.pending_data ( 30 | seqid BIGSERIAL, 31 | tablename TEXT NOT NULL CONSTRAINT tablename_exists CHECK (to_regclass(tablename) IS NOT NULL), 32 | op "char" NOT NULL CONSTRAINT op_in_diu CHECK (op IN ('d', 'i', 'u')), 33 | xid BIGINT NOT NULL, 34 | -- We use JSON over JSONB because there is no need to perform 35 | -- operations on the data; this additionally lets us store the 36 | -- keys in column-order, which makes the packets much easier 37 | -- to read while debugging. 38 | olddata JSON CONSTRAINT olddata_is_null_for_inserts CHECK ((olddata IS NULL) = (op = 'i')), 39 | newdata JSON CONSTRAINT newdata_is_null_for_deletes CHECK ((newdata IS NULL) = (op = 'd')), 40 | oldctid TID, 41 | trgdepth INTEGER 42 | ); 43 | 44 | ALTER TABLE dbmirror2.pending_data 45 | ADD CONSTRAINT pending_data_pkey 46 | PRIMARY KEY (seqid); 47 | 48 | CREATE INDEX pending_data_idx_xid_seqid 49 | ON dbmirror2.pending_data (xid, seqid); 50 | 51 | CREATE INDEX pending_data_idx_oldctid_xid 52 | ON dbmirror2.pending_data (oldctid, xid); 53 | 54 | COMMIT; 55 | -------------------------------------------------------------------------------- /mbdata/sql/documentation/DropFunctions.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | -------------------------------------------------------------------------------- /mbdata/sql/documentation/DropIndexes.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | -------------------------------------------------------------------------------- /mbdata/sql/documentation/DropReplicationTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'documentation'; 5 | 6 | DROP TRIGGER IF EXISTS reptg_l_area_area_example ON l_area_area_example; 7 | DROP TRIGGER IF EXISTS reptg_l_area_artist_example ON l_area_artist_example; 8 | DROP TRIGGER IF EXISTS reptg_l_area_event_example ON l_area_event_example; 9 | DROP TRIGGER IF EXISTS reptg_l_area_genre_example ON l_area_genre_example; 10 | DROP TRIGGER IF EXISTS reptg_l_area_instrument_example ON l_area_instrument_example; 11 | DROP TRIGGER IF EXISTS reptg_l_area_label_example ON l_area_label_example; 12 | DROP TRIGGER IF EXISTS reptg_l_area_mood_example ON l_area_mood_example; 13 | DROP TRIGGER IF EXISTS reptg_l_area_place_example ON l_area_place_example; 14 | DROP TRIGGER IF EXISTS reptg_l_area_recording_example ON l_area_recording_example; 15 | DROP TRIGGER IF EXISTS reptg_l_area_release_example ON l_area_release_example; 16 | DROP TRIGGER IF EXISTS reptg_l_area_release_group_example ON l_area_release_group_example; 17 | DROP TRIGGER IF EXISTS reptg_l_area_series_example ON l_area_series_example; 18 | DROP TRIGGER IF EXISTS reptg_l_area_url_example ON l_area_url_example; 19 | DROP TRIGGER IF EXISTS reptg_l_area_work_example ON l_area_work_example; 20 | DROP TRIGGER IF EXISTS reptg_l_artist_artist_example ON l_artist_artist_example; 21 | DROP TRIGGER IF EXISTS reptg_l_artist_event_example ON l_artist_event_example; 22 | DROP TRIGGER IF EXISTS reptg_l_artist_genre_example ON l_artist_genre_example; 23 | DROP TRIGGER IF EXISTS reptg_l_artist_instrument_example ON l_artist_instrument_example; 24 | DROP TRIGGER IF EXISTS reptg_l_artist_label_example ON l_artist_label_example; 25 | DROP TRIGGER IF EXISTS reptg_l_artist_mood_example ON l_artist_mood_example; 26 | DROP TRIGGER IF EXISTS reptg_l_artist_place_example ON l_artist_place_example; 27 | DROP TRIGGER IF EXISTS reptg_l_artist_recording_example ON l_artist_recording_example; 28 | DROP TRIGGER IF EXISTS reptg_l_artist_release_example ON l_artist_release_example; 29 | DROP TRIGGER IF EXISTS reptg_l_artist_release_group_example ON l_artist_release_group_example; 30 | DROP TRIGGER IF EXISTS reptg_l_artist_series_example ON l_artist_series_example; 31 | DROP TRIGGER IF EXISTS reptg_l_artist_url_example ON l_artist_url_example; 32 | DROP TRIGGER IF EXISTS reptg_l_artist_work_example ON l_artist_work_example; 33 | DROP TRIGGER IF EXISTS reptg_l_event_event_example ON l_event_event_example; 34 | DROP TRIGGER IF EXISTS reptg_l_event_genre_example ON l_event_genre_example; 35 | DROP TRIGGER IF EXISTS reptg_l_event_instrument_example ON l_event_instrument_example; 36 | DROP TRIGGER IF EXISTS reptg_l_event_label_example ON l_event_label_example; 37 | DROP TRIGGER IF EXISTS reptg_l_event_mood_example ON l_event_mood_example; 38 | DROP TRIGGER IF EXISTS reptg_l_event_place_example ON l_event_place_example; 39 | DROP TRIGGER IF EXISTS reptg_l_event_recording_example ON l_event_recording_example; 40 | DROP TRIGGER IF EXISTS reptg_l_event_release_example ON l_event_release_example; 41 | DROP TRIGGER IF EXISTS reptg_l_event_release_group_example ON l_event_release_group_example; 42 | DROP TRIGGER IF EXISTS reptg_l_event_series_example ON l_event_series_example; 43 | DROP TRIGGER IF EXISTS reptg_l_event_url_example ON l_event_url_example; 44 | DROP TRIGGER IF EXISTS reptg_l_event_work_example ON l_event_work_example; 45 | DROP TRIGGER IF EXISTS reptg_l_genre_genre_example ON l_genre_genre_example; 46 | DROP TRIGGER IF EXISTS reptg_l_genre_instrument_example ON l_genre_instrument_example; 47 | DROP TRIGGER IF EXISTS reptg_l_genre_label_example ON l_genre_label_example; 48 | DROP TRIGGER IF EXISTS reptg_l_genre_mood_example ON l_genre_mood_example; 49 | DROP TRIGGER IF EXISTS reptg_l_genre_place_example ON l_genre_place_example; 50 | DROP TRIGGER IF EXISTS reptg_l_genre_recording_example ON l_genre_recording_example; 51 | DROP TRIGGER IF EXISTS reptg_l_genre_release_example ON l_genre_release_example; 52 | DROP TRIGGER IF EXISTS reptg_l_genre_release_group_example ON l_genre_release_group_example; 53 | DROP TRIGGER IF EXISTS reptg_l_genre_series_example ON l_genre_series_example; 54 | DROP TRIGGER IF EXISTS reptg_l_genre_url_example ON l_genre_url_example; 55 | DROP TRIGGER IF EXISTS reptg_l_genre_work_example ON l_genre_work_example; 56 | DROP TRIGGER IF EXISTS reptg_l_instrument_instrument_example ON l_instrument_instrument_example; 57 | DROP TRIGGER IF EXISTS reptg_l_instrument_label_example ON l_instrument_label_example; 58 | DROP TRIGGER IF EXISTS reptg_l_instrument_mood_example ON l_instrument_mood_example; 59 | DROP TRIGGER IF EXISTS reptg_l_instrument_place_example ON l_instrument_place_example; 60 | DROP TRIGGER IF EXISTS reptg_l_instrument_recording_example ON l_instrument_recording_example; 61 | DROP TRIGGER IF EXISTS reptg_l_instrument_release_example ON l_instrument_release_example; 62 | DROP TRIGGER IF EXISTS reptg_l_instrument_release_group_example ON l_instrument_release_group_example; 63 | DROP TRIGGER IF EXISTS reptg_l_instrument_series_example ON l_instrument_series_example; 64 | DROP TRIGGER IF EXISTS reptg_l_instrument_url_example ON l_instrument_url_example; 65 | DROP TRIGGER IF EXISTS reptg_l_instrument_work_example ON l_instrument_work_example; 66 | DROP TRIGGER IF EXISTS reptg_l_label_label_example ON l_label_label_example; 67 | DROP TRIGGER IF EXISTS reptg_l_label_mood_example ON l_label_mood_example; 68 | DROP TRIGGER IF EXISTS reptg_l_label_place_example ON l_label_place_example; 69 | DROP TRIGGER IF EXISTS reptg_l_label_recording_example ON l_label_recording_example; 70 | DROP TRIGGER IF EXISTS reptg_l_label_release_example ON l_label_release_example; 71 | DROP TRIGGER IF EXISTS reptg_l_label_release_group_example ON l_label_release_group_example; 72 | DROP TRIGGER IF EXISTS reptg_l_label_series_example ON l_label_series_example; 73 | DROP TRIGGER IF EXISTS reptg_l_label_url_example ON l_label_url_example; 74 | DROP TRIGGER IF EXISTS reptg_l_label_work_example ON l_label_work_example; 75 | DROP TRIGGER IF EXISTS reptg_l_mood_mood_example ON l_mood_mood_example; 76 | DROP TRIGGER IF EXISTS reptg_l_mood_place_example ON l_mood_place_example; 77 | DROP TRIGGER IF EXISTS reptg_l_mood_recording_example ON l_mood_recording_example; 78 | DROP TRIGGER IF EXISTS reptg_l_mood_release_example ON l_mood_release_example; 79 | DROP TRIGGER IF EXISTS reptg_l_mood_release_group_example ON l_mood_release_group_example; 80 | DROP TRIGGER IF EXISTS reptg_l_mood_series_example ON l_mood_series_example; 81 | DROP TRIGGER IF EXISTS reptg_l_mood_url_example ON l_mood_url_example; 82 | DROP TRIGGER IF EXISTS reptg_l_mood_work_example ON l_mood_work_example; 83 | DROP TRIGGER IF EXISTS reptg_l_place_place_example ON l_place_place_example; 84 | DROP TRIGGER IF EXISTS reptg_l_place_recording_example ON l_place_recording_example; 85 | DROP TRIGGER IF EXISTS reptg_l_place_release_example ON l_place_release_example; 86 | DROP TRIGGER IF EXISTS reptg_l_place_release_group_example ON l_place_release_group_example; 87 | DROP TRIGGER IF EXISTS reptg_l_place_series_example ON l_place_series_example; 88 | DROP TRIGGER IF EXISTS reptg_l_place_url_example ON l_place_url_example; 89 | DROP TRIGGER IF EXISTS reptg_l_place_work_example ON l_place_work_example; 90 | DROP TRIGGER IF EXISTS reptg_l_recording_recording_example ON l_recording_recording_example; 91 | DROP TRIGGER IF EXISTS reptg_l_recording_release_example ON l_recording_release_example; 92 | DROP TRIGGER IF EXISTS reptg_l_recording_release_group_example ON l_recording_release_group_example; 93 | DROP TRIGGER IF EXISTS reptg_l_recording_series_example ON l_recording_series_example; 94 | DROP TRIGGER IF EXISTS reptg_l_recording_url_example ON l_recording_url_example; 95 | DROP TRIGGER IF EXISTS reptg_l_recording_work_example ON l_recording_work_example; 96 | DROP TRIGGER IF EXISTS reptg_l_release_group_release_group_example ON l_release_group_release_group_example; 97 | DROP TRIGGER IF EXISTS reptg_l_release_group_series_example ON l_release_group_series_example; 98 | DROP TRIGGER IF EXISTS reptg_l_release_group_url_example ON l_release_group_url_example; 99 | DROP TRIGGER IF EXISTS reptg_l_release_group_work_example ON l_release_group_work_example; 100 | DROP TRIGGER IF EXISTS reptg_l_release_release_example ON l_release_release_example; 101 | DROP TRIGGER IF EXISTS reptg_l_release_release_group_example ON l_release_release_group_example; 102 | DROP TRIGGER IF EXISTS reptg_l_release_series_example ON l_release_series_example; 103 | DROP TRIGGER IF EXISTS reptg_l_release_url_example ON l_release_url_example; 104 | DROP TRIGGER IF EXISTS reptg_l_release_work_example ON l_release_work_example; 105 | DROP TRIGGER IF EXISTS reptg_l_series_series_example ON l_series_series_example; 106 | DROP TRIGGER IF EXISTS reptg_l_series_url_example ON l_series_url_example; 107 | DROP TRIGGER IF EXISTS reptg_l_series_work_example ON l_series_work_example; 108 | DROP TRIGGER IF EXISTS reptg_l_url_url_example ON l_url_url_example; 109 | DROP TRIGGER IF EXISTS reptg_l_url_work_example ON l_url_work_example; 110 | DROP TRIGGER IF EXISTS reptg_l_work_work_example ON l_work_work_example; 111 | DROP TRIGGER IF EXISTS reptg_link_type_documentation ON link_type_documentation; 112 | -------------------------------------------------------------------------------- /mbdata/sql/documentation/DropReplicationTriggers2.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'documentation'; 5 | 6 | DROP TRIGGER IF EXISTS reptg2_l_area_area_example ON l_area_area_example; 7 | DROP TRIGGER IF EXISTS reptg2_l_area_artist_example ON l_area_artist_example; 8 | DROP TRIGGER IF EXISTS reptg2_l_area_event_example ON l_area_event_example; 9 | DROP TRIGGER IF EXISTS reptg2_l_area_genre_example ON l_area_genre_example; 10 | DROP TRIGGER IF EXISTS reptg2_l_area_instrument_example ON l_area_instrument_example; 11 | DROP TRIGGER IF EXISTS reptg2_l_area_label_example ON l_area_label_example; 12 | DROP TRIGGER IF EXISTS reptg2_l_area_mood_example ON l_area_mood_example; 13 | DROP TRIGGER IF EXISTS reptg2_l_area_place_example ON l_area_place_example; 14 | DROP TRIGGER IF EXISTS reptg2_l_area_recording_example ON l_area_recording_example; 15 | DROP TRIGGER IF EXISTS reptg2_l_area_release_example ON l_area_release_example; 16 | DROP TRIGGER IF EXISTS reptg2_l_area_release_group_example ON l_area_release_group_example; 17 | DROP TRIGGER IF EXISTS reptg2_l_area_series_example ON l_area_series_example; 18 | DROP TRIGGER IF EXISTS reptg2_l_area_url_example ON l_area_url_example; 19 | DROP TRIGGER IF EXISTS reptg2_l_area_work_example ON l_area_work_example; 20 | DROP TRIGGER IF EXISTS reptg2_l_artist_artist_example ON l_artist_artist_example; 21 | DROP TRIGGER IF EXISTS reptg2_l_artist_event_example ON l_artist_event_example; 22 | DROP TRIGGER IF EXISTS reptg2_l_artist_genre_example ON l_artist_genre_example; 23 | DROP TRIGGER IF EXISTS reptg2_l_artist_instrument_example ON l_artist_instrument_example; 24 | DROP TRIGGER IF EXISTS reptg2_l_artist_label_example ON l_artist_label_example; 25 | DROP TRIGGER IF EXISTS reptg2_l_artist_mood_example ON l_artist_mood_example; 26 | DROP TRIGGER IF EXISTS reptg2_l_artist_place_example ON l_artist_place_example; 27 | DROP TRIGGER IF EXISTS reptg2_l_artist_recording_example ON l_artist_recording_example; 28 | DROP TRIGGER IF EXISTS reptg2_l_artist_release_example ON l_artist_release_example; 29 | DROP TRIGGER IF EXISTS reptg2_l_artist_release_group_example ON l_artist_release_group_example; 30 | DROP TRIGGER IF EXISTS reptg2_l_artist_series_example ON l_artist_series_example; 31 | DROP TRIGGER IF EXISTS reptg2_l_artist_url_example ON l_artist_url_example; 32 | DROP TRIGGER IF EXISTS reptg2_l_artist_work_example ON l_artist_work_example; 33 | DROP TRIGGER IF EXISTS reptg2_l_event_event_example ON l_event_event_example; 34 | DROP TRIGGER IF EXISTS reptg2_l_event_genre_example ON l_event_genre_example; 35 | DROP TRIGGER IF EXISTS reptg2_l_event_instrument_example ON l_event_instrument_example; 36 | DROP TRIGGER IF EXISTS reptg2_l_event_label_example ON l_event_label_example; 37 | DROP TRIGGER IF EXISTS reptg2_l_event_mood_example ON l_event_mood_example; 38 | DROP TRIGGER IF EXISTS reptg2_l_event_place_example ON l_event_place_example; 39 | DROP TRIGGER IF EXISTS reptg2_l_event_recording_example ON l_event_recording_example; 40 | DROP TRIGGER IF EXISTS reptg2_l_event_release_example ON l_event_release_example; 41 | DROP TRIGGER IF EXISTS reptg2_l_event_release_group_example ON l_event_release_group_example; 42 | DROP TRIGGER IF EXISTS reptg2_l_event_series_example ON l_event_series_example; 43 | DROP TRIGGER IF EXISTS reptg2_l_event_url_example ON l_event_url_example; 44 | DROP TRIGGER IF EXISTS reptg2_l_event_work_example ON l_event_work_example; 45 | DROP TRIGGER IF EXISTS reptg2_l_genre_genre_example ON l_genre_genre_example; 46 | DROP TRIGGER IF EXISTS reptg2_l_genre_instrument_example ON l_genre_instrument_example; 47 | DROP TRIGGER IF EXISTS reptg2_l_genre_label_example ON l_genre_label_example; 48 | DROP TRIGGER IF EXISTS reptg2_l_genre_mood_example ON l_genre_mood_example; 49 | DROP TRIGGER IF EXISTS reptg2_l_genre_place_example ON l_genre_place_example; 50 | DROP TRIGGER IF EXISTS reptg2_l_genre_recording_example ON l_genre_recording_example; 51 | DROP TRIGGER IF EXISTS reptg2_l_genre_release_example ON l_genre_release_example; 52 | DROP TRIGGER IF EXISTS reptg2_l_genre_release_group_example ON l_genre_release_group_example; 53 | DROP TRIGGER IF EXISTS reptg2_l_genre_series_example ON l_genre_series_example; 54 | DROP TRIGGER IF EXISTS reptg2_l_genre_url_example ON l_genre_url_example; 55 | DROP TRIGGER IF EXISTS reptg2_l_genre_work_example ON l_genre_work_example; 56 | DROP TRIGGER IF EXISTS reptg2_l_instrument_instrument_example ON l_instrument_instrument_example; 57 | DROP TRIGGER IF EXISTS reptg2_l_instrument_label_example ON l_instrument_label_example; 58 | DROP TRIGGER IF EXISTS reptg2_l_instrument_mood_example ON l_instrument_mood_example; 59 | DROP TRIGGER IF EXISTS reptg2_l_instrument_place_example ON l_instrument_place_example; 60 | DROP TRIGGER IF EXISTS reptg2_l_instrument_recording_example ON l_instrument_recording_example; 61 | DROP TRIGGER IF EXISTS reptg2_l_instrument_release_example ON l_instrument_release_example; 62 | DROP TRIGGER IF EXISTS reptg2_l_instrument_release_group_example ON l_instrument_release_group_example; 63 | DROP TRIGGER IF EXISTS reptg2_l_instrument_series_example ON l_instrument_series_example; 64 | DROP TRIGGER IF EXISTS reptg2_l_instrument_url_example ON l_instrument_url_example; 65 | DROP TRIGGER IF EXISTS reptg2_l_instrument_work_example ON l_instrument_work_example; 66 | DROP TRIGGER IF EXISTS reptg2_l_label_label_example ON l_label_label_example; 67 | DROP TRIGGER IF EXISTS reptg2_l_label_mood_example ON l_label_mood_example; 68 | DROP TRIGGER IF EXISTS reptg2_l_label_place_example ON l_label_place_example; 69 | DROP TRIGGER IF EXISTS reptg2_l_label_recording_example ON l_label_recording_example; 70 | DROP TRIGGER IF EXISTS reptg2_l_label_release_example ON l_label_release_example; 71 | DROP TRIGGER IF EXISTS reptg2_l_label_release_group_example ON l_label_release_group_example; 72 | DROP TRIGGER IF EXISTS reptg2_l_label_series_example ON l_label_series_example; 73 | DROP TRIGGER IF EXISTS reptg2_l_label_url_example ON l_label_url_example; 74 | DROP TRIGGER IF EXISTS reptg2_l_label_work_example ON l_label_work_example; 75 | DROP TRIGGER IF EXISTS reptg2_l_mood_mood_example ON l_mood_mood_example; 76 | DROP TRIGGER IF EXISTS reptg2_l_mood_place_example ON l_mood_place_example; 77 | DROP TRIGGER IF EXISTS reptg2_l_mood_recording_example ON l_mood_recording_example; 78 | DROP TRIGGER IF EXISTS reptg2_l_mood_release_example ON l_mood_release_example; 79 | DROP TRIGGER IF EXISTS reptg2_l_mood_release_group_example ON l_mood_release_group_example; 80 | DROP TRIGGER IF EXISTS reptg2_l_mood_series_example ON l_mood_series_example; 81 | DROP TRIGGER IF EXISTS reptg2_l_mood_url_example ON l_mood_url_example; 82 | DROP TRIGGER IF EXISTS reptg2_l_mood_work_example ON l_mood_work_example; 83 | DROP TRIGGER IF EXISTS reptg2_l_place_place_example ON l_place_place_example; 84 | DROP TRIGGER IF EXISTS reptg2_l_place_recording_example ON l_place_recording_example; 85 | DROP TRIGGER IF EXISTS reptg2_l_place_release_example ON l_place_release_example; 86 | DROP TRIGGER IF EXISTS reptg2_l_place_release_group_example ON l_place_release_group_example; 87 | DROP TRIGGER IF EXISTS reptg2_l_place_series_example ON l_place_series_example; 88 | DROP TRIGGER IF EXISTS reptg2_l_place_url_example ON l_place_url_example; 89 | DROP TRIGGER IF EXISTS reptg2_l_place_work_example ON l_place_work_example; 90 | DROP TRIGGER IF EXISTS reptg2_l_recording_recording_example ON l_recording_recording_example; 91 | DROP TRIGGER IF EXISTS reptg2_l_recording_release_example ON l_recording_release_example; 92 | DROP TRIGGER IF EXISTS reptg2_l_recording_release_group_example ON l_recording_release_group_example; 93 | DROP TRIGGER IF EXISTS reptg2_l_recording_series_example ON l_recording_series_example; 94 | DROP TRIGGER IF EXISTS reptg2_l_recording_url_example ON l_recording_url_example; 95 | DROP TRIGGER IF EXISTS reptg2_l_recording_work_example ON l_recording_work_example; 96 | DROP TRIGGER IF EXISTS reptg2_l_release_group_release_group_example ON l_release_group_release_group_example; 97 | DROP TRIGGER IF EXISTS reptg2_l_release_group_series_example ON l_release_group_series_example; 98 | DROP TRIGGER IF EXISTS reptg2_l_release_group_url_example ON l_release_group_url_example; 99 | DROP TRIGGER IF EXISTS reptg2_l_release_group_work_example ON l_release_group_work_example; 100 | DROP TRIGGER IF EXISTS reptg2_l_release_release_example ON l_release_release_example; 101 | DROP TRIGGER IF EXISTS reptg2_l_release_release_group_example ON l_release_release_group_example; 102 | DROP TRIGGER IF EXISTS reptg2_l_release_series_example ON l_release_series_example; 103 | DROP TRIGGER IF EXISTS reptg2_l_release_url_example ON l_release_url_example; 104 | DROP TRIGGER IF EXISTS reptg2_l_release_work_example ON l_release_work_example; 105 | DROP TRIGGER IF EXISTS reptg2_l_series_series_example ON l_series_series_example; 106 | DROP TRIGGER IF EXISTS reptg2_l_series_url_example ON l_series_url_example; 107 | DROP TRIGGER IF EXISTS reptg2_l_series_work_example ON l_series_work_example; 108 | DROP TRIGGER IF EXISTS reptg2_l_url_url_example ON l_url_url_example; 109 | DROP TRIGGER IF EXISTS reptg2_l_url_work_example ON l_url_work_example; 110 | DROP TRIGGER IF EXISTS reptg2_l_work_work_example ON l_work_work_example; 111 | DROP TRIGGER IF EXISTS reptg2_link_type_documentation ON link_type_documentation; 112 | -------------------------------------------------------------------------------- /mbdata/sql/documentation/DropSearchIndexes.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | -------------------------------------------------------------------------------- /mbdata/sql/documentation/DropTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'documentation'; 5 | 6 | DROP TABLE l_area_area_example; 7 | DROP TABLE l_area_artist_example; 8 | DROP TABLE l_area_event_example; 9 | DROP TABLE l_area_genre_example; 10 | DROP TABLE l_area_instrument_example; 11 | DROP TABLE l_area_label_example; 12 | DROP TABLE l_area_mood_example; 13 | DROP TABLE l_area_place_example; 14 | DROP TABLE l_area_recording_example; 15 | DROP TABLE l_area_release_example; 16 | DROP TABLE l_area_release_group_example; 17 | DROP TABLE l_area_series_example; 18 | DROP TABLE l_area_url_example; 19 | DROP TABLE l_area_work_example; 20 | DROP TABLE l_artist_artist_example; 21 | DROP TABLE l_artist_event_example; 22 | DROP TABLE l_artist_genre_example; 23 | DROP TABLE l_artist_instrument_example; 24 | DROP TABLE l_artist_label_example; 25 | DROP TABLE l_artist_mood_example; 26 | DROP TABLE l_artist_place_example; 27 | DROP TABLE l_artist_recording_example; 28 | DROP TABLE l_artist_release_example; 29 | DROP TABLE l_artist_release_group_example; 30 | DROP TABLE l_artist_series_example; 31 | DROP TABLE l_artist_url_example; 32 | DROP TABLE l_artist_work_example; 33 | DROP TABLE l_event_event_example; 34 | DROP TABLE l_event_genre_example; 35 | DROP TABLE l_event_instrument_example; 36 | DROP TABLE l_event_label_example; 37 | DROP TABLE l_event_mood_example; 38 | DROP TABLE l_event_place_example; 39 | DROP TABLE l_event_recording_example; 40 | DROP TABLE l_event_release_example; 41 | DROP TABLE l_event_release_group_example; 42 | DROP TABLE l_event_series_example; 43 | DROP TABLE l_event_url_example; 44 | DROP TABLE l_event_work_example; 45 | DROP TABLE l_genre_genre_example; 46 | DROP TABLE l_genre_instrument_example; 47 | DROP TABLE l_genre_label_example; 48 | DROP TABLE l_genre_mood_example; 49 | DROP TABLE l_genre_place_example; 50 | DROP TABLE l_genre_recording_example; 51 | DROP TABLE l_genre_release_example; 52 | DROP TABLE l_genre_release_group_example; 53 | DROP TABLE l_genre_series_example; 54 | DROP TABLE l_genre_url_example; 55 | DROP TABLE l_genre_work_example; 56 | DROP TABLE l_instrument_instrument_example; 57 | DROP TABLE l_instrument_label_example; 58 | DROP TABLE l_instrument_mood_example; 59 | DROP TABLE l_instrument_place_example; 60 | DROP TABLE l_instrument_recording_example; 61 | DROP TABLE l_instrument_release_example; 62 | DROP TABLE l_instrument_release_group_example; 63 | DROP TABLE l_instrument_series_example; 64 | DROP TABLE l_instrument_url_example; 65 | DROP TABLE l_instrument_work_example; 66 | DROP TABLE l_label_label_example; 67 | DROP TABLE l_label_mood_example; 68 | DROP TABLE l_label_place_example; 69 | DROP TABLE l_label_recording_example; 70 | DROP TABLE l_label_release_example; 71 | DROP TABLE l_label_release_group_example; 72 | DROP TABLE l_label_series_example; 73 | DROP TABLE l_label_url_example; 74 | DROP TABLE l_label_work_example; 75 | DROP TABLE l_mood_mood_example; 76 | DROP TABLE l_mood_place_example; 77 | DROP TABLE l_mood_recording_example; 78 | DROP TABLE l_mood_release_example; 79 | DROP TABLE l_mood_release_group_example; 80 | DROP TABLE l_mood_series_example; 81 | DROP TABLE l_mood_url_example; 82 | DROP TABLE l_mood_work_example; 83 | DROP TABLE l_place_place_example; 84 | DROP TABLE l_place_recording_example; 85 | DROP TABLE l_place_release_example; 86 | DROP TABLE l_place_release_group_example; 87 | DROP TABLE l_place_series_example; 88 | DROP TABLE l_place_url_example; 89 | DROP TABLE l_place_work_example; 90 | DROP TABLE l_recording_recording_example; 91 | DROP TABLE l_recording_release_example; 92 | DROP TABLE l_recording_release_group_example; 93 | DROP TABLE l_recording_series_example; 94 | DROP TABLE l_recording_url_example; 95 | DROP TABLE l_recording_work_example; 96 | DROP TABLE l_release_group_release_group_example; 97 | DROP TABLE l_release_group_series_example; 98 | DROP TABLE l_release_group_url_example; 99 | DROP TABLE l_release_group_work_example; 100 | DROP TABLE l_release_release_example; 101 | DROP TABLE l_release_release_group_example; 102 | DROP TABLE l_release_series_example; 103 | DROP TABLE l_release_url_example; 104 | DROP TABLE l_release_work_example; 105 | DROP TABLE l_series_series_example; 106 | DROP TABLE l_series_url_example; 107 | DROP TABLE l_series_work_example; 108 | DROP TABLE l_url_url_example; 109 | DROP TABLE l_url_work_example; 110 | DROP TABLE l_work_work_example; 111 | DROP TABLE link_type_documentation; 112 | -------------------------------------------------------------------------------- /mbdata/sql/documentation/DropTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | -------------------------------------------------------------------------------- /mbdata/sql/documentation/DropViews.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | -------------------------------------------------------------------------------- /mbdata/sql/documentation/SetSequences.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | -------------------------------------------------------------------------------- /mbdata/sql/documentation/TruncateTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'documentation'; 5 | 6 | TRUNCATE TABLE l_area_area_example RESTART IDENTITY CASCADE; 7 | TRUNCATE TABLE l_area_artist_example RESTART IDENTITY CASCADE; 8 | TRUNCATE TABLE l_area_event_example RESTART IDENTITY CASCADE; 9 | TRUNCATE TABLE l_area_genre_example RESTART IDENTITY CASCADE; 10 | TRUNCATE TABLE l_area_instrument_example RESTART IDENTITY CASCADE; 11 | TRUNCATE TABLE l_area_label_example RESTART IDENTITY CASCADE; 12 | TRUNCATE TABLE l_area_mood_example RESTART IDENTITY CASCADE; 13 | TRUNCATE TABLE l_area_place_example RESTART IDENTITY CASCADE; 14 | TRUNCATE TABLE l_area_recording_example RESTART IDENTITY CASCADE; 15 | TRUNCATE TABLE l_area_release_example RESTART IDENTITY CASCADE; 16 | TRUNCATE TABLE l_area_release_group_example RESTART IDENTITY CASCADE; 17 | TRUNCATE TABLE l_area_series_example RESTART IDENTITY CASCADE; 18 | TRUNCATE TABLE l_area_url_example RESTART IDENTITY CASCADE; 19 | TRUNCATE TABLE l_area_work_example RESTART IDENTITY CASCADE; 20 | TRUNCATE TABLE l_artist_artist_example RESTART IDENTITY CASCADE; 21 | TRUNCATE TABLE l_artist_event_example RESTART IDENTITY CASCADE; 22 | TRUNCATE TABLE l_artist_genre_example RESTART IDENTITY CASCADE; 23 | TRUNCATE TABLE l_artist_instrument_example RESTART IDENTITY CASCADE; 24 | TRUNCATE TABLE l_artist_label_example RESTART IDENTITY CASCADE; 25 | TRUNCATE TABLE l_artist_mood_example RESTART IDENTITY CASCADE; 26 | TRUNCATE TABLE l_artist_place_example RESTART IDENTITY CASCADE; 27 | TRUNCATE TABLE l_artist_recording_example RESTART IDENTITY CASCADE; 28 | TRUNCATE TABLE l_artist_release_example RESTART IDENTITY CASCADE; 29 | TRUNCATE TABLE l_artist_release_group_example RESTART IDENTITY CASCADE; 30 | TRUNCATE TABLE l_artist_series_example RESTART IDENTITY CASCADE; 31 | TRUNCATE TABLE l_artist_url_example RESTART IDENTITY CASCADE; 32 | TRUNCATE TABLE l_artist_work_example RESTART IDENTITY CASCADE; 33 | TRUNCATE TABLE l_event_event_example RESTART IDENTITY CASCADE; 34 | TRUNCATE TABLE l_event_genre_example RESTART IDENTITY CASCADE; 35 | TRUNCATE TABLE l_event_instrument_example RESTART IDENTITY CASCADE; 36 | TRUNCATE TABLE l_event_label_example RESTART IDENTITY CASCADE; 37 | TRUNCATE TABLE l_event_mood_example RESTART IDENTITY CASCADE; 38 | TRUNCATE TABLE l_event_place_example RESTART IDENTITY CASCADE; 39 | TRUNCATE TABLE l_event_recording_example RESTART IDENTITY CASCADE; 40 | TRUNCATE TABLE l_event_release_example RESTART IDENTITY CASCADE; 41 | TRUNCATE TABLE l_event_release_group_example RESTART IDENTITY CASCADE; 42 | TRUNCATE TABLE l_event_series_example RESTART IDENTITY CASCADE; 43 | TRUNCATE TABLE l_event_url_example RESTART IDENTITY CASCADE; 44 | TRUNCATE TABLE l_event_work_example RESTART IDENTITY CASCADE; 45 | TRUNCATE TABLE l_genre_genre_example RESTART IDENTITY CASCADE; 46 | TRUNCATE TABLE l_genre_instrument_example RESTART IDENTITY CASCADE; 47 | TRUNCATE TABLE l_genre_label_example RESTART IDENTITY CASCADE; 48 | TRUNCATE TABLE l_genre_mood_example RESTART IDENTITY CASCADE; 49 | TRUNCATE TABLE l_genre_place_example RESTART IDENTITY CASCADE; 50 | TRUNCATE TABLE l_genre_recording_example RESTART IDENTITY CASCADE; 51 | TRUNCATE TABLE l_genre_release_example RESTART IDENTITY CASCADE; 52 | TRUNCATE TABLE l_genre_release_group_example RESTART IDENTITY CASCADE; 53 | TRUNCATE TABLE l_genre_series_example RESTART IDENTITY CASCADE; 54 | TRUNCATE TABLE l_genre_url_example RESTART IDENTITY CASCADE; 55 | TRUNCATE TABLE l_genre_work_example RESTART IDENTITY CASCADE; 56 | TRUNCATE TABLE l_instrument_instrument_example RESTART IDENTITY CASCADE; 57 | TRUNCATE TABLE l_instrument_label_example RESTART IDENTITY CASCADE; 58 | TRUNCATE TABLE l_instrument_mood_example RESTART IDENTITY CASCADE; 59 | TRUNCATE TABLE l_instrument_place_example RESTART IDENTITY CASCADE; 60 | TRUNCATE TABLE l_instrument_recording_example RESTART IDENTITY CASCADE; 61 | TRUNCATE TABLE l_instrument_release_example RESTART IDENTITY CASCADE; 62 | TRUNCATE TABLE l_instrument_release_group_example RESTART IDENTITY CASCADE; 63 | TRUNCATE TABLE l_instrument_series_example RESTART IDENTITY CASCADE; 64 | TRUNCATE TABLE l_instrument_url_example RESTART IDENTITY CASCADE; 65 | TRUNCATE TABLE l_instrument_work_example RESTART IDENTITY CASCADE; 66 | TRUNCATE TABLE l_label_label_example RESTART IDENTITY CASCADE; 67 | TRUNCATE TABLE l_label_mood_example RESTART IDENTITY CASCADE; 68 | TRUNCATE TABLE l_label_place_example RESTART IDENTITY CASCADE; 69 | TRUNCATE TABLE l_label_recording_example RESTART IDENTITY CASCADE; 70 | TRUNCATE TABLE l_label_release_example RESTART IDENTITY CASCADE; 71 | TRUNCATE TABLE l_label_release_group_example RESTART IDENTITY CASCADE; 72 | TRUNCATE TABLE l_label_series_example RESTART IDENTITY CASCADE; 73 | TRUNCATE TABLE l_label_url_example RESTART IDENTITY CASCADE; 74 | TRUNCATE TABLE l_label_work_example RESTART IDENTITY CASCADE; 75 | TRUNCATE TABLE l_mood_mood_example RESTART IDENTITY CASCADE; 76 | TRUNCATE TABLE l_mood_place_example RESTART IDENTITY CASCADE; 77 | TRUNCATE TABLE l_mood_recording_example RESTART IDENTITY CASCADE; 78 | TRUNCATE TABLE l_mood_release_example RESTART IDENTITY CASCADE; 79 | TRUNCATE TABLE l_mood_release_group_example RESTART IDENTITY CASCADE; 80 | TRUNCATE TABLE l_mood_series_example RESTART IDENTITY CASCADE; 81 | TRUNCATE TABLE l_mood_url_example RESTART IDENTITY CASCADE; 82 | TRUNCATE TABLE l_mood_work_example RESTART IDENTITY CASCADE; 83 | TRUNCATE TABLE l_place_place_example RESTART IDENTITY CASCADE; 84 | TRUNCATE TABLE l_place_recording_example RESTART IDENTITY CASCADE; 85 | TRUNCATE TABLE l_place_release_example RESTART IDENTITY CASCADE; 86 | TRUNCATE TABLE l_place_release_group_example RESTART IDENTITY CASCADE; 87 | TRUNCATE TABLE l_place_series_example RESTART IDENTITY CASCADE; 88 | TRUNCATE TABLE l_place_url_example RESTART IDENTITY CASCADE; 89 | TRUNCATE TABLE l_place_work_example RESTART IDENTITY CASCADE; 90 | TRUNCATE TABLE l_recording_recording_example RESTART IDENTITY CASCADE; 91 | TRUNCATE TABLE l_recording_release_example RESTART IDENTITY CASCADE; 92 | TRUNCATE TABLE l_recording_release_group_example RESTART IDENTITY CASCADE; 93 | TRUNCATE TABLE l_recording_series_example RESTART IDENTITY CASCADE; 94 | TRUNCATE TABLE l_recording_url_example RESTART IDENTITY CASCADE; 95 | TRUNCATE TABLE l_recording_work_example RESTART IDENTITY CASCADE; 96 | TRUNCATE TABLE l_release_group_release_group_example RESTART IDENTITY CASCADE; 97 | TRUNCATE TABLE l_release_group_series_example RESTART IDENTITY CASCADE; 98 | TRUNCATE TABLE l_release_group_url_example RESTART IDENTITY CASCADE; 99 | TRUNCATE TABLE l_release_group_work_example RESTART IDENTITY CASCADE; 100 | TRUNCATE TABLE l_release_release_example RESTART IDENTITY CASCADE; 101 | TRUNCATE TABLE l_release_release_group_example RESTART IDENTITY CASCADE; 102 | TRUNCATE TABLE l_release_series_example RESTART IDENTITY CASCADE; 103 | TRUNCATE TABLE l_release_url_example RESTART IDENTITY CASCADE; 104 | TRUNCATE TABLE l_release_work_example RESTART IDENTITY CASCADE; 105 | TRUNCATE TABLE l_series_series_example RESTART IDENTITY CASCADE; 106 | TRUNCATE TABLE l_series_url_example RESTART IDENTITY CASCADE; 107 | TRUNCATE TABLE l_series_work_example RESTART IDENTITY CASCADE; 108 | TRUNCATE TABLE l_url_url_example RESTART IDENTITY CASCADE; 109 | TRUNCATE TABLE l_url_work_example RESTART IDENTITY CASCADE; 110 | TRUNCATE TABLE l_work_work_example RESTART IDENTITY CASCADE; 111 | TRUNCATE TABLE link_type_documentation RESTART IDENTITY CASCADE; 112 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/CreateEditFKConstraints.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | SET search_path = 'event_art_archive'; 4 | 5 | ALTER TABLE event_art 6 | ADD CONSTRAINT event_art_fk_edit 7 | FOREIGN KEY (edit) 8 | REFERENCES musicbrainz.edit(id); 9 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/CreateFKConstraints.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | ALTER TABLE art_type 7 | ADD CONSTRAINT art_type_fk_parent 8 | FOREIGN KEY (parent) 9 | REFERENCES event_art_archive.art_type(id); 10 | 11 | ALTER TABLE event_art 12 | ADD CONSTRAINT event_art_fk_event 13 | FOREIGN KEY (event) 14 | REFERENCES musicbrainz.event(id) 15 | ON DELETE CASCADE; 16 | 17 | ALTER TABLE event_art 18 | ADD CONSTRAINT event_art_fk_mime_type 19 | FOREIGN KEY (mime_type) 20 | REFERENCES cover_art_archive.image_type(mime_type); 21 | 22 | ALTER TABLE event_art_type 23 | ADD CONSTRAINT event_art_type_fk_id 24 | FOREIGN KEY (id) 25 | REFERENCES event_art_archive.event_art(id) 26 | ON DELETE CASCADE; 27 | 28 | ALTER TABLE event_art_type 29 | ADD CONSTRAINT event_art_type_fk_type_id 30 | FOREIGN KEY (type_id) 31 | REFERENCES event_art_archive.art_type(id); 32 | 33 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/CreateFunctions.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | SET search_path = 'event_art_archive'; 4 | 5 | CREATE OR REPLACE FUNCTION materialize_eaa_presence() RETURNS trigger AS $$ 6 | BEGIN 7 | -- On delete, set the presence flag to 'absent' if there's no more 8 | -- event art 9 | IF TG_OP = 'DELETE' THEN 10 | IF NOT EXISTS ( 11 | SELECT TRUE FROM event_art_archive.event_art 12 | WHERE event = OLD.event 13 | ) THEN 14 | UPDATE musicbrainz.event_meta 15 | SET event_art_presence = 'absent' 16 | WHERE id = OLD.event; 17 | END IF; 18 | END IF; 19 | 20 | -- On insert, set the presence flag to 'present' if it was previously 21 | -- 'absent' 22 | IF TG_OP = 'INSERT' THEN 23 | CASE ( 24 | SELECT event_art_presence FROM musicbrainz.event_meta 25 | WHERE id = NEW.event 26 | ) 27 | WHEN 'absent' THEN 28 | UPDATE musicbrainz.event_meta 29 | SET event_art_presence = 'present' 30 | WHERE id = NEW.event; 31 | WHEN 'darkened' THEN 32 | RAISE EXCEPTION 'This event has been darkened and cannot have new event art'; 33 | ELSE 34 | END CASE; 35 | END IF; 36 | 37 | RETURN NULL; 38 | END; 39 | $$ LANGUAGE 'plpgsql'; 40 | 41 | CREATE OR REPLACE FUNCTION resequence_positions(event_id INT) RETURNS void AS $$ 42 | BEGIN 43 | UPDATE event_art_archive.event_art 44 | SET ordering = recalculated.row_number 45 | FROM ( 46 | SELECT *, 47 | row_number() OVER (PARTITION BY event ORDER BY ordering ASC) 48 | FROM event_art_archive.event_art 49 | WHERE event_art.event = event_id 50 | ) recalculated 51 | WHERE recalculated.id = event_art.id AND 52 | recalculated.row_number != event_art.ordering; 53 | END; 54 | $$ LANGUAGE 'plpgsql'; 55 | 56 | CREATE OR REPLACE FUNCTION resequence_event_art_trigger() RETURNS trigger AS $$ 57 | BEGIN 58 | IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN 59 | PERFORM event_art_archive.resequence_positions(NEW.event); 60 | END IF; 61 | 62 | IF (TG_OP = 'DELETE') OR 63 | (TG_OP = 'UPDATE' AND NEW.event != OLD.event) 64 | THEN 65 | PERFORM event_art_archive.resequence_positions(OLD.event); 66 | END IF; 67 | 68 | RETURN NULL; 69 | END; 70 | $$ LANGUAGE 'plpgsql'; 71 | 72 | COMMIT; 73 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/CreateIndexes.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | SET search_path = 'event_art_archive'; 6 | 7 | CREATE INDEX event_art_idx_event ON event_art (event); 8 | CREATE UNIQUE INDEX art_type_idx_gid ON art_type (gid); 9 | 10 | COMMIT; 11 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/CreatePrimaryKeys.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | ALTER TABLE art_type ADD CONSTRAINT art_type_pkey PRIMARY KEY (id); 7 | ALTER TABLE event_art ADD CONSTRAINT event_art_pkey PRIMARY KEY (id); 8 | ALTER TABLE event_art_type ADD CONSTRAINT event_art_type_pkey PRIMARY KEY (id, type_id); 9 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/CreateReplicationTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'event_art_archive', musicbrainz, public; 5 | 6 | BEGIN; 7 | 8 | CREATE TRIGGER "reptg_art_type" 9 | AFTER INSERT OR DELETE OR UPDATE ON "art_type" 10 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" ('verbose'); 11 | 12 | CREATE TRIGGER "reptg_event_art" 13 | AFTER INSERT OR DELETE OR UPDATE ON "event_art" 14 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" ('verbose'); 15 | 16 | CREATE TRIGGER "reptg_event_art_type" 17 | AFTER INSERT OR DELETE OR UPDATE ON "event_art_type" 18 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" ('verbose'); 19 | 20 | COMMIT; 21 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/CreateReplicationTriggers2.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'event_art_archive', musicbrainz, public; 5 | 6 | BEGIN; 7 | 8 | CREATE TRIGGER reptg2_art_type 9 | AFTER INSERT OR DELETE OR UPDATE ON art_type 10 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 11 | 12 | CREATE TRIGGER reptg2_event_art 13 | AFTER INSERT OR DELETE OR UPDATE ON event_art 14 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 15 | 16 | CREATE TRIGGER reptg2_event_art_type 17 | AFTER INSERT OR DELETE OR UPDATE ON event_art_type 18 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 19 | 20 | COMMIT; 21 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/CreateTables.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | SET search_path = 'event_art_archive'; 6 | 7 | CREATE TABLE art_type ( -- replicate (verbose) 8 | id SERIAL NOT NULL, -- PK 9 | name TEXT NOT NULL, 10 | parent INTEGER, -- references event_art_archive.art_type.id 11 | child_order INTEGER NOT NULL DEFAULT 0, 12 | description TEXT, 13 | gid uuid NOT NULL 14 | ); 15 | 16 | CREATE TABLE event_art ( -- replicate (verbose) 17 | id BIGINT NOT NULL, -- PK 18 | event INTEGER NOT NULL, -- references musicbrainz.event.id CASCADE 19 | comment TEXT NOT NULL DEFAULT '', 20 | edit INTEGER NOT NULL, -- separately references musicbrainz.edit.id 21 | ordering INTEGER NOT NULL CHECK (ordering > 0), 22 | date_uploaded TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, 23 | edits_pending INTEGER NOT NULL DEFAULT 0 CHECK (edits_pending >= 0), 24 | mime_type TEXT NOT NULL, -- references cover_art_archive.image_type.mime_type 25 | filesize INTEGER, 26 | thumb_250_filesize INTEGER, 27 | thumb_500_filesize INTEGER, 28 | thumb_1200_filesize INTEGER 29 | ); 30 | 31 | CREATE TABLE event_art_type ( -- replicate (verbose) 32 | id BIGINT NOT NULL, -- PK, references event_art_archive.event_art.id CASCADE, 33 | type_id INTEGER NOT NULL -- PK, references event_art_archive.art_type.id, 34 | ); 35 | 36 | COMMIT; 37 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/CreateTriggers.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | SET search_path = 'event_art_archive'; 4 | 5 | CREATE TRIGGER update_event_art AFTER INSERT OR DELETE 6 | ON event_art_archive.event_art 7 | FOR EACH ROW EXECUTE PROCEDURE materialize_eaa_presence(); 8 | 9 | CREATE CONSTRAINT TRIGGER resquence_event_art AFTER INSERT OR UPDATE OR DELETE 10 | ON event_art_archive.event_art DEFERRABLE INITIALLY DEFERRED 11 | FOR EACH ROW EXECUTE PROCEDURE resequence_event_art_trigger(); 12 | 13 | COMMIT; 14 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/CreateViews.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | SET search_path = 'event_art_archive'; 6 | 7 | CREATE OR REPLACE VIEW index_listing AS 8 | SELECT event_art.*, 9 | (edit.close_time IS NOT NULL) AS approved, 10 | coalesce(event_art.id = (SELECT id FROM event_art_archive.event_art_type 11 | JOIN event_art_archive.event_art ea_front USING (id) 12 | WHERE ea_front.event = event_art.event 13 | AND type_id = 1 14 | ORDER BY ea_front.ordering 15 | LIMIT 1), FALSE) AS is_front, 16 | array(SELECT art_type.name 17 | FROM event_art_archive.event_art_type 18 | JOIN event_art_archive.art_type ON event_art_type.type_id = art_type.id 19 | WHERE event_art_type.id = event_art.id) AS types 20 | FROM event_art_archive.event_art 21 | LEFT JOIN musicbrainz.edit ON edit.id = event_art.edit; 22 | 23 | COMMIT; 24 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/DropFKConstraints.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | ALTER TABLE art_type DROP CONSTRAINT IF EXISTS art_type_fk_parent; 7 | ALTER TABLE event_art DROP CONSTRAINT IF EXISTS event_art_fk_event; 8 | ALTER TABLE event_art DROP CONSTRAINT IF EXISTS event_art_fk_edit; 9 | ALTER TABLE event_art DROP CONSTRAINT IF EXISTS event_art_fk_mime_type; 10 | ALTER TABLE event_art_type DROP CONSTRAINT IF EXISTS event_art_type_fk_id; 11 | ALTER TABLE event_art_type DROP CONSTRAINT IF EXISTS event_art_type_fk_type_id; 12 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/DropFunctions.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | DROP FUNCTION materialize_eaa_presence(); 7 | DROP FUNCTION resequence_event_art_trigger(); 8 | DROP FUNCTION resequence_positions(event_id INT); 9 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/DropIndexes.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | DROP INDEX art_type_idx_gid; 7 | DROP INDEX event_art_idx_event; 8 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/DropPrimaryKeys.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | ALTER TABLE art_type DROP CONSTRAINT IF EXISTS art_type_pkey; 7 | ALTER TABLE event_art DROP CONSTRAINT IF EXISTS event_art_pkey; 8 | ALTER TABLE event_art_type DROP CONSTRAINT IF EXISTS event_art_type_pkey; 9 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/DropReplicationTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | DROP TRIGGER IF EXISTS reptg_art_type ON art_type; 7 | DROP TRIGGER IF EXISTS reptg_event_art ON event_art; 8 | DROP TRIGGER IF EXISTS reptg_event_art_type ON event_art_type; 9 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/DropReplicationTriggers2.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | DROP TRIGGER IF EXISTS reptg2_art_type ON art_type; 7 | DROP TRIGGER IF EXISTS reptg2_event_art ON event_art; 8 | DROP TRIGGER IF EXISTS reptg2_event_art_type ON event_art_type; 9 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/DropTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | DROP TABLE art_type; 7 | DROP TABLE event_art; 8 | DROP TABLE event_art_type; 9 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/DropTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | DROP TRIGGER IF EXISTS update_event_art ON event_art_archive.event_art; 7 | DROP TRIGGER IF EXISTS resquence_event_art ON event_art_archive.event_art; 8 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/DropViews.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | DROP VIEW index_listing; 7 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/SetSequences.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | SELECT setval('art_type_id_seq', COALESCE((SELECT MAX(id) FROM art_type), 0) + 1, FALSE); 7 | -------------------------------------------------------------------------------- /mbdata/sql/eaa/TruncateTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'event_art_archive'; 5 | 6 | TRUNCATE TABLE art_type RESTART IDENTITY CASCADE; 7 | TRUNCATE TABLE event_art RESTART IDENTITY CASCADE; 8 | TRUNCATE TABLE event_art_type RESTART IDENTITY CASCADE; 9 | -------------------------------------------------------------------------------- /mbdata/sql/json_dump/CreateIndexes.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | SET search_path = json_dump; 6 | 7 | CREATE UNIQUE INDEX tmp_checked_entities_idx_uniq ON tmp_checked_entities (id, entity_type); 8 | 9 | CREATE INDEX deleted_entities_idx_replication_sequence ON deleted_entities (replication_sequence); 10 | 11 | COMMIT; 12 | -------------------------------------------------------------------------------- /mbdata/sql/json_dump/CreatePrimaryKeys.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = json_dump, public; 5 | 6 | ALTER TABLE area_json ADD CONSTRAINT area_json_pkey PRIMARY KEY (id, replication_sequence); 7 | ALTER TABLE artist_json ADD CONSTRAINT artist_json_pkey PRIMARY KEY (id, replication_sequence); 8 | ALTER TABLE deleted_entities ADD CONSTRAINT deleted_entities_pkey PRIMARY KEY (entity_type, id); 9 | ALTER TABLE event_json ADD CONSTRAINT event_json_pkey PRIMARY KEY (id, replication_sequence); 10 | ALTER TABLE instrument_json ADD CONSTRAINT instrument_json_pkey PRIMARY KEY (id, replication_sequence); 11 | ALTER TABLE label_json ADD CONSTRAINT label_json_pkey PRIMARY KEY (id, replication_sequence); 12 | ALTER TABLE place_json ADD CONSTRAINT place_json_pkey PRIMARY KEY (id, replication_sequence); 13 | ALTER TABLE recording_json ADD CONSTRAINT recording_json_pkey PRIMARY KEY (id, replication_sequence); 14 | ALTER TABLE release_group_json ADD CONSTRAINT release_group_json_pkey PRIMARY KEY (id, replication_sequence); 15 | ALTER TABLE release_json ADD CONSTRAINT release_json_pkey PRIMARY KEY (id, replication_sequence); 16 | ALTER TABLE series_json ADD CONSTRAINT series_json_pkey PRIMARY KEY (id, replication_sequence); 17 | ALTER TABLE work_json ADD CONSTRAINT work_json_pkey PRIMARY KEY (id, replication_sequence); 18 | -------------------------------------------------------------------------------- /mbdata/sql/json_dump/CreateTables.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | SET search_path = json_dump, public; 6 | 7 | CREATE TABLE control ( 8 | last_processed_replication_sequence INTEGER, 9 | full_json_dump_replication_sequence INTEGER 10 | ); 11 | 12 | CREATE TABLE tmp_checked_entities ( 13 | id INTEGER NOT NULL, 14 | entity_type VARCHAR(50) NOT NULL 15 | ); 16 | 17 | CREATE TABLE deleted_entities ( 18 | entity_type VARCHAR(50) NOT NULL, -- PK 19 | id INTEGER NOT NULL, -- PK 20 | replication_sequence INTEGER NOT NULL 21 | ); 22 | 23 | CREATE TABLE area_json ( 24 | id INTEGER NOT NULL, -- PK 25 | replication_sequence INTEGER NOT NULL, -- PK 26 | json JSONB NOT NULL, 27 | last_modified TIMESTAMP WITH TIME ZONE 28 | ); 29 | 30 | CREATE TABLE artist_json ( 31 | id INTEGER NOT NULL, -- PK 32 | replication_sequence INTEGER NOT NULL, -- PK 33 | json JSONB NOT NULL, 34 | last_modified TIMESTAMP WITH TIME ZONE 35 | ); 36 | 37 | CREATE TABLE event_json ( 38 | id INTEGER NOT NULL, -- PK 39 | replication_sequence INTEGER NOT NULL, -- PK 40 | json JSONB NOT NULL, 41 | last_modified TIMESTAMP WITH TIME ZONE 42 | ); 43 | 44 | CREATE TABLE instrument_json ( 45 | id INTEGER NOT NULL, -- PK 46 | replication_sequence INTEGER NOT NULL, -- PK 47 | json JSONB NOT NULL, 48 | last_modified TIMESTAMP WITH TIME ZONE 49 | ); 50 | 51 | CREATE TABLE label_json ( 52 | id INTEGER NOT NULL, -- PK 53 | replication_sequence INTEGER NOT NULL, -- PK 54 | json JSONB NOT NULL, 55 | last_modified TIMESTAMP WITH TIME ZONE 56 | ); 57 | 58 | CREATE TABLE place_json ( 59 | id INTEGER NOT NULL, -- PK 60 | replication_sequence INTEGER NOT NULL, -- PK 61 | json JSONB NOT NULL, 62 | last_modified TIMESTAMP WITH TIME ZONE 63 | ); 64 | 65 | CREATE TABLE recording_json ( 66 | id INTEGER NOT NULL, -- PK 67 | replication_sequence INTEGER NOT NULL, -- PK 68 | json JSONB NOT NULL, 69 | last_modified TIMESTAMP WITH TIME ZONE 70 | ); 71 | 72 | CREATE TABLE release_json ( 73 | id INTEGER NOT NULL, -- PK 74 | replication_sequence INTEGER NOT NULL, -- PK 75 | json JSONB NOT NULL, 76 | last_modified TIMESTAMP WITH TIME ZONE 77 | ); 78 | 79 | CREATE TABLE release_group_json ( 80 | id INTEGER NOT NULL, -- PK 81 | replication_sequence INTEGER NOT NULL, -- PK 82 | json JSONB NOT NULL, 83 | last_modified TIMESTAMP WITH TIME ZONE 84 | ); 85 | 86 | CREATE TABLE series_json ( 87 | id INTEGER NOT NULL, -- PK 88 | replication_sequence INTEGER NOT NULL, -- PK 89 | json JSONB NOT NULL, 90 | last_modified TIMESTAMP WITH TIME ZONE 91 | ); 92 | 93 | CREATE TABLE work_json ( 94 | id INTEGER NOT NULL, -- PK 95 | replication_sequence INTEGER NOT NULL, -- PK 96 | json JSONB NOT NULL, 97 | last_modified TIMESTAMP WITH TIME ZONE 98 | ); 99 | 100 | COMMIT; 101 | -------------------------------------------------------------------------------- /mbdata/sql/json_dump/DropFKConstraints.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = json_dump, public; 5 | 6 | ALTER TABLE area_lastmod DROP CONSTRAINT IF EXISTS area_lastmod_fk_id; 7 | ALTER TABLE artist_lastmod DROP CONSTRAINT IF EXISTS artist_lastmod_fk_id; 8 | ALTER TABLE event_lastmod DROP CONSTRAINT IF EXISTS event_lastmod_fk_id; 9 | ALTER TABLE instrument_lastmod DROP CONSTRAINT IF EXISTS instrument_lastmod_fk_id; 10 | ALTER TABLE label_lastmod DROP CONSTRAINT IF EXISTS label_lastmod_fk_id; 11 | ALTER TABLE place_lastmod DROP CONSTRAINT IF EXISTS place_lastmod_fk_id; 12 | ALTER TABLE recording_lastmod DROP CONSTRAINT IF EXISTS recording_lastmod_fk_id; 13 | ALTER TABLE release_group_lastmod DROP CONSTRAINT IF EXISTS release_group_lastmod_fk_id; 14 | ALTER TABLE release_lastmod DROP CONSTRAINT IF EXISTS release_lastmod_fk_id; 15 | ALTER TABLE series_lastmod DROP CONSTRAINT IF EXISTS series_lastmod_fk_id; 16 | ALTER TABLE work_lastmod DROP CONSTRAINT IF EXISTS work_lastmod_fk_id; 17 | -------------------------------------------------------------------------------- /mbdata/sql/json_dump/DropIndexes.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = json_dump, public; 5 | 6 | DROP INDEX deleted_entities_idx_replication_sequence; 7 | DROP INDEX tmp_checked_entities_idx_uniq; 8 | -------------------------------------------------------------------------------- /mbdata/sql/json_dump/DropPrimaryKeys.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = json_dump, public; 5 | 6 | ALTER TABLE area_json DROP CONSTRAINT IF EXISTS area_json_pkey; 7 | ALTER TABLE artist_json DROP CONSTRAINT IF EXISTS artist_json_pkey; 8 | ALTER TABLE deleted_entities DROP CONSTRAINT IF EXISTS deleted_entities_pkey; 9 | ALTER TABLE event_json DROP CONSTRAINT IF EXISTS event_json_pkey; 10 | ALTER TABLE instrument_json DROP CONSTRAINT IF EXISTS instrument_json_pkey; 11 | ALTER TABLE label_json DROP CONSTRAINT IF EXISTS label_json_pkey; 12 | ALTER TABLE place_json DROP CONSTRAINT IF EXISTS place_json_pkey; 13 | ALTER TABLE recording_json DROP CONSTRAINT IF EXISTS recording_json_pkey; 14 | ALTER TABLE release_group_json DROP CONSTRAINT IF EXISTS release_group_json_pkey; 15 | ALTER TABLE release_json DROP CONSTRAINT IF EXISTS release_json_pkey; 16 | ALTER TABLE series_json DROP CONSTRAINT IF EXISTS series_json_pkey; 17 | ALTER TABLE work_json DROP CONSTRAINT IF EXISTS work_json_pkey; 18 | -------------------------------------------------------------------------------- /mbdata/sql/json_dump/DropTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = json_dump, public; 5 | 6 | DROP TABLE area_json; 7 | DROP TABLE artist_json; 8 | DROP TABLE control; 9 | DROP TABLE deleted_entities; 10 | DROP TABLE event_json; 11 | DROP TABLE instrument_json; 12 | DROP TABLE label_json; 13 | DROP TABLE place_json; 14 | DROP TABLE recording_json; 15 | DROP TABLE release_group_json; 16 | DROP TABLE release_json; 17 | DROP TABLE series_json; 18 | DROP TABLE tmp_checked_entities; 19 | DROP TABLE work_json; 20 | -------------------------------------------------------------------------------- /mbdata/sql/json_dump/TruncateTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = json_dump, public; 5 | 6 | TRUNCATE TABLE area_json RESTART IDENTITY CASCADE; 7 | TRUNCATE TABLE artist_json RESTART IDENTITY CASCADE; 8 | TRUNCATE TABLE control RESTART IDENTITY CASCADE; 9 | TRUNCATE TABLE deleted_entities RESTART IDENTITY CASCADE; 10 | TRUNCATE TABLE event_json RESTART IDENTITY CASCADE; 11 | TRUNCATE TABLE instrument_json RESTART IDENTITY CASCADE; 12 | TRUNCATE TABLE label_json RESTART IDENTITY CASCADE; 13 | TRUNCATE TABLE place_json RESTART IDENTITY CASCADE; 14 | TRUNCATE TABLE recording_json RESTART IDENTITY CASCADE; 15 | TRUNCATE TABLE release_group_json RESTART IDENTITY CASCADE; 16 | TRUNCATE TABLE release_json RESTART IDENTITY CASCADE; 17 | TRUNCATE TABLE series_json RESTART IDENTITY CASCADE; 18 | TRUNCATE TABLE tmp_checked_entities RESTART IDENTITY CASCADE; 19 | TRUNCATE TABLE work_json RESTART IDENTITY CASCADE; 20 | -------------------------------------------------------------------------------- /mbdata/sql/report/CreateTables.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | SET search_path = report; 4 | 5 | CREATE TABLE report.index ( 6 | report_name TEXT NOT NULL PRIMARY KEY, 7 | generated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now() 8 | ); 9 | 10 | COMMIT; 11 | -------------------------------------------------------------------------------- /mbdata/sql/report/TruncateTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = report; 5 | 6 | -------------------------------------------------------------------------------- /mbdata/sql/sitemaps/CreateFKConstraints.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'sitemaps'; 5 | 6 | ALTER TABLE artist_lastmod 7 | ADD CONSTRAINT artist_lastmod_fk_id 8 | FOREIGN KEY (id) 9 | REFERENCES musicbrainz.artist(id) 10 | ON DELETE CASCADE; 11 | 12 | ALTER TABLE label_lastmod 13 | ADD CONSTRAINT label_lastmod_fk_id 14 | FOREIGN KEY (id) 15 | REFERENCES musicbrainz.label(id) 16 | ON DELETE CASCADE; 17 | 18 | ALTER TABLE place_lastmod 19 | ADD CONSTRAINT place_lastmod_fk_id 20 | FOREIGN KEY (id) 21 | REFERENCES musicbrainz.place(id) 22 | ON DELETE CASCADE; 23 | 24 | ALTER TABLE recording_lastmod 25 | ADD CONSTRAINT recording_lastmod_fk_id 26 | FOREIGN KEY (id) 27 | REFERENCES musicbrainz.recording(id) 28 | ON DELETE CASCADE; 29 | 30 | ALTER TABLE release_group_lastmod 31 | ADD CONSTRAINT release_group_lastmod_fk_id 32 | FOREIGN KEY (id) 33 | REFERENCES musicbrainz.release_group(id) 34 | ON DELETE CASCADE; 35 | 36 | ALTER TABLE release_lastmod 37 | ADD CONSTRAINT release_lastmod_fk_id 38 | FOREIGN KEY (id) 39 | REFERENCES musicbrainz.release(id) 40 | ON DELETE CASCADE; 41 | 42 | ALTER TABLE work_lastmod 43 | ADD CONSTRAINT work_lastmod_fk_id 44 | FOREIGN KEY (id) 45 | REFERENCES musicbrainz.work(id) 46 | ON DELETE CASCADE; 47 | 48 | -------------------------------------------------------------------------------- /mbdata/sql/sitemaps/CreateIndexes.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | SET search_path = 'sitemaps'; 6 | 7 | CREATE UNIQUE INDEX artist_lastmod_idx_url ON artist_lastmod (url); 8 | CREATE UNIQUE INDEX tmp_checked_entities_idx_uniq ON tmp_checked_entities (id, entity_type); 9 | CREATE UNIQUE INDEX label_lastmod_idx_url ON label_lastmod (url); 10 | CREATE UNIQUE INDEX place_lastmod_idx_url ON place_lastmod (url); 11 | CREATE UNIQUE INDEX recording_lastmod_idx_url ON recording_lastmod (url); 12 | CREATE UNIQUE INDEX release_lastmod_idx_url ON release_lastmod (url); 13 | CREATE UNIQUE INDEX release_group_lastmod_idx_url ON release_group_lastmod (url); 14 | CREATE UNIQUE INDEX work_lastmod_idx_url ON work_lastmod (url); 15 | 16 | COMMIT; 17 | -------------------------------------------------------------------------------- /mbdata/sql/sitemaps/CreateTables.sql: -------------------------------------------------------------------------------- 1 | \set ON_ERROR_STOP 1 2 | 3 | BEGIN; 4 | 5 | SET search_path = 'sitemaps'; 6 | 7 | CREATE TABLE control ( 8 | last_processed_replication_sequence INTEGER, 9 | overall_sitemaps_replication_sequence INTEGER, 10 | building_overall_sitemaps BOOLEAN NOT NULL 11 | ); 12 | 13 | CREATE TABLE tmp_checked_entities ( 14 | id INTEGER NOT NULL, 15 | entity_type VARCHAR(50) NOT NULL 16 | ); 17 | 18 | CREATE TABLE artist_lastmod ( 19 | id INTEGER NOT NULL, -- FK, references musicbrainz.artist.id CASCADE 20 | url VARCHAR(128) NOT NULL, 21 | paginated BOOLEAN NOT NULL, 22 | sitemap_suffix_key VARCHAR(50) NOT NULL, 23 | jsonld_sha1 BYTEA NOT NULL, 24 | last_modified TIMESTAMP WITH TIME ZONE NOT NULL, 25 | replication_sequence INTEGER NOT NULL 26 | ); 27 | 28 | CREATE TABLE label_lastmod ( 29 | id INTEGER NOT NULL, -- FK, references musicbrainz.label.id CASCADE 30 | url VARCHAR(128) NOT NULL, 31 | paginated BOOLEAN NOT NULL, 32 | sitemap_suffix_key VARCHAR(50) NOT NULL, 33 | jsonld_sha1 BYTEA NOT NULL, 34 | last_modified TIMESTAMP WITH TIME ZONE NOT NULL, 35 | replication_sequence INTEGER NOT NULL 36 | ); 37 | 38 | CREATE TABLE place_lastmod ( 39 | id INTEGER NOT NULL, -- FK, references musicbrainz.place.id CASCADE 40 | url VARCHAR(128) NOT NULL, 41 | paginated BOOLEAN NOT NULL, 42 | sitemap_suffix_key VARCHAR(50) NOT NULL, 43 | jsonld_sha1 BYTEA NOT NULL, 44 | last_modified TIMESTAMP WITH TIME ZONE NOT NULL, 45 | replication_sequence INTEGER NOT NULL 46 | ); 47 | 48 | CREATE TABLE recording_lastmod ( 49 | id INTEGER NOT NULL, -- FK, references musicbrainz.recording.id CASCADE 50 | url VARCHAR(128) NOT NULL, 51 | paginated BOOLEAN NOT NULL, 52 | sitemap_suffix_key VARCHAR(50) NOT NULL, 53 | jsonld_sha1 BYTEA NOT NULL, 54 | last_modified TIMESTAMP WITH TIME ZONE NOT NULL, 55 | replication_sequence INTEGER NOT NULL 56 | ); 57 | 58 | CREATE TABLE release_lastmod ( 59 | id INTEGER NOT NULL, -- FK, references musicbrainz.release.id CASCADE 60 | url VARCHAR(128) NOT NULL, 61 | paginated BOOLEAN NOT NULL, 62 | sitemap_suffix_key VARCHAR(50) NOT NULL, 63 | jsonld_sha1 BYTEA NOT NULL, 64 | last_modified TIMESTAMP WITH TIME ZONE NOT NULL, 65 | replication_sequence INTEGER NOT NULL 66 | ); 67 | 68 | CREATE TABLE release_group_lastmod ( 69 | id INTEGER NOT NULL, -- FK, references musicbrainz.release_group.id CASCADE 70 | url VARCHAR(128) NOT NULL, 71 | paginated BOOLEAN NOT NULL, 72 | sitemap_suffix_key VARCHAR(50) NOT NULL, 73 | jsonld_sha1 BYTEA NOT NULL, 74 | last_modified TIMESTAMP WITH TIME ZONE NOT NULL, 75 | replication_sequence INTEGER NOT NULL 76 | ); 77 | 78 | CREATE TABLE work_lastmod ( 79 | id INTEGER NOT NULL, -- FK, references musicbrainz.work.id CASCADE 80 | url VARCHAR(128) NOT NULL, 81 | paginated BOOLEAN NOT NULL, 82 | sitemap_suffix_key VARCHAR(50) NOT NULL, 83 | jsonld_sha1 BYTEA NOT NULL, 84 | last_modified TIMESTAMP WITH TIME ZONE NOT NULL, 85 | replication_sequence INTEGER NOT NULL 86 | ); 87 | 88 | COMMIT; 89 | -------------------------------------------------------------------------------- /mbdata/sql/sitemaps/DropFKConstraints.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'sitemaps'; 5 | 6 | ALTER TABLE artist_lastmod DROP CONSTRAINT IF EXISTS artist_lastmod_fk_id; 7 | ALTER TABLE label_lastmod DROP CONSTRAINT IF EXISTS label_lastmod_fk_id; 8 | ALTER TABLE place_lastmod DROP CONSTRAINT IF EXISTS place_lastmod_fk_id; 9 | ALTER TABLE recording_lastmod DROP CONSTRAINT IF EXISTS recording_lastmod_fk_id; 10 | ALTER TABLE release_group_lastmod DROP CONSTRAINT IF EXISTS release_group_lastmod_fk_id; 11 | ALTER TABLE release_lastmod DROP CONSTRAINT IF EXISTS release_lastmod_fk_id; 12 | ALTER TABLE work_lastmod DROP CONSTRAINT IF EXISTS work_lastmod_fk_id; 13 | -------------------------------------------------------------------------------- /mbdata/sql/sitemaps/DropIndexes.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'sitemaps'; 5 | 6 | DROP INDEX artist_lastmod_idx_url; 7 | DROP INDEX label_lastmod_idx_url; 8 | DROP INDEX place_lastmod_idx_url; 9 | DROP INDEX recording_lastmod_idx_url; 10 | DROP INDEX release_group_lastmod_idx_url; 11 | DROP INDEX release_lastmod_idx_url; 12 | DROP INDEX tmp_checked_entities_idx_uniq; 13 | DROP INDEX work_lastmod_idx_url; 14 | -------------------------------------------------------------------------------- /mbdata/sql/sitemaps/DropTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'sitemaps'; 5 | 6 | DROP TABLE artist_lastmod; 7 | DROP TABLE control; 8 | DROP TABLE label_lastmod; 9 | DROP TABLE place_lastmod; 10 | DROP TABLE recording_lastmod; 11 | DROP TABLE release_group_lastmod; 12 | DROP TABLE release_lastmod; 13 | DROP TABLE tmp_checked_entities; 14 | DROP TABLE work_lastmod; 15 | -------------------------------------------------------------------------------- /mbdata/sql/sitemaps/TruncateTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'sitemaps'; 5 | 6 | TRUNCATE TABLE artist_lastmod RESTART IDENTITY CASCADE; 7 | TRUNCATE TABLE control RESTART IDENTITY CASCADE; 8 | TRUNCATE TABLE label_lastmod RESTART IDENTITY CASCADE; 9 | TRUNCATE TABLE place_lastmod RESTART IDENTITY CASCADE; 10 | TRUNCATE TABLE recording_lastmod RESTART IDENTITY CASCADE; 11 | TRUNCATE TABLE release_group_lastmod RESTART IDENTITY CASCADE; 12 | TRUNCATE TABLE release_lastmod RESTART IDENTITY CASCADE; 13 | TRUNCATE TABLE tmp_checked_entities RESTART IDENTITY CASCADE; 14 | TRUNCATE TABLE work_lastmod RESTART IDENTITY CASCADE; 15 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/CreateIndexes.sql: -------------------------------------------------------------------------------- 1 | SET search_path = 'statistics'; 2 | 3 | \set ON_ERROR_STOP 1 4 | BEGIN; 5 | 6 | CREATE INDEX statistic_name ON statistic (name); 7 | CREATE UNIQUE INDEX statistic_name_date_collected ON statistic (name, date_collected); 8 | 9 | COMMIT; 10 | 11 | -- vi: set ts=4 sw=4 et : 12 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/CreatePrimaryKeys.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'statistics'; 5 | 6 | ALTER TABLE statistic ADD CONSTRAINT statistic_pkey PRIMARY KEY (id); 7 | ALTER TABLE statistic_event ADD CONSTRAINT statistic_event_pkey PRIMARY KEY (date); 8 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/CreateReplicationTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'statistics', musicbrainz, public; 5 | 6 | BEGIN; 7 | 8 | CREATE TRIGGER "reptg_statistic" 9 | AFTER INSERT OR DELETE OR UPDATE ON "statistic" 10 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" (); 11 | 12 | CREATE TRIGGER "reptg_statistic_event" 13 | AFTER INSERT OR DELETE OR UPDATE ON "statistic_event" 14 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" (); 15 | 16 | COMMIT; 17 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/CreateReplicationTriggers2.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'statistics', musicbrainz, public; 5 | 6 | BEGIN; 7 | 8 | CREATE TRIGGER reptg2_statistic 9 | AFTER INSERT OR DELETE OR UPDATE ON statistic 10 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 11 | 12 | CREATE TRIGGER reptg2_statistic_event 13 | AFTER INSERT OR DELETE OR UPDATE ON statistic_event 14 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 15 | 16 | COMMIT; 17 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/CreateTables.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | SET search_path = 'statistics'; 4 | 5 | CREATE TABLE statistic ( -- replicate 6 | id SERIAL, 7 | name VARCHAR(100) NOT NULL, 8 | value INTEGER NOT NULL, 9 | date_collected date NOT NULL DEFAULT NOW() 10 | ); 11 | 12 | CREATE TABLE statistic_event ( -- replicate 13 | date DATE NOT NULL CHECK (date >= '2000-01-01'), -- PK 14 | title TEXT NOT NULL, 15 | link TEXT NOT NULL, 16 | description TEXT NOT NULL 17 | ); 18 | 19 | COMMIT; 20 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/DropIndexes.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'statistics'; 5 | 6 | DROP INDEX statistic_name; 7 | DROP INDEX statistic_name_date_collected; 8 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/DropPrimaryKeys.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'statistics'; 5 | 6 | ALTER TABLE statistic DROP CONSTRAINT IF EXISTS statistic_pkey; 7 | ALTER TABLE statistic_event DROP CONSTRAINT IF EXISTS statistic_event_pkey; 8 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/DropReplicationTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'statistics'; 5 | 6 | DROP TRIGGER IF EXISTS reptg_statistic ON statistic; 7 | DROP TRIGGER IF EXISTS reptg_statistic_event ON statistic_event; 8 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/DropReplicationTriggers2.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'statistics'; 5 | 6 | DROP TRIGGER IF EXISTS reptg2_statistic ON statistic; 7 | DROP TRIGGER IF EXISTS reptg2_statistic_event ON statistic_event; 8 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/DropTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'statistics'; 5 | 6 | DROP TABLE statistic; 7 | DROP TABLE statistic_event; 8 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/SetSequences.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'statistics'; 5 | 6 | SELECT setval('statistic_id_seq', COALESCE((SELECT MAX(id) FROM statistic), 0) + 1, FALSE); 7 | -------------------------------------------------------------------------------- /mbdata/sql/statistics/TruncateTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'statistics'; 5 | 6 | TRUNCATE TABLE statistic RESTART IDENTITY CASCADE; 7 | TRUNCATE TABLE statistic_event RESTART IDENTITY CASCADE; 8 | -------------------------------------------------------------------------------- /mbdata/sql/wikidocs/CreatePrimaryKeys.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'wikidocs'; 5 | 6 | ALTER TABLE wikidocs_index ADD CONSTRAINT wikidocs_index_pkey PRIMARY KEY (page_name); 7 | -------------------------------------------------------------------------------- /mbdata/sql/wikidocs/CreateReplicationTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'wikidocs', musicbrainz, public; 5 | 6 | BEGIN; 7 | 8 | CREATE TRIGGER "reptg_wikidocs_index" 9 | AFTER INSERT OR DELETE OR UPDATE ON "wikidocs_index" 10 | FOR EACH ROW EXECUTE PROCEDURE "recordchange" (); 11 | 12 | COMMIT; 13 | -------------------------------------------------------------------------------- /mbdata/sql/wikidocs/CreateReplicationTriggers2.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'wikidocs', musicbrainz, public; 5 | 6 | BEGIN; 7 | 8 | CREATE TRIGGER reptg2_wikidocs_index 9 | AFTER INSERT OR DELETE OR UPDATE ON wikidocs_index 10 | FOR EACH ROW EXECUTE PROCEDURE dbmirror2.recordchange(); 11 | 12 | COMMIT; 13 | -------------------------------------------------------------------------------- /mbdata/sql/wikidocs/CreateTables.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | SET search_path = 'wikidocs'; 4 | 5 | CREATE TABLE wikidocs_index ( -- replicate 6 | page_name TEXT NOT NULL, -- PK 7 | revision INTEGER NOT NULL 8 | ); 9 | 10 | COMMIT; 11 | -------------------------------------------------------------------------------- /mbdata/sql/wikidocs/DropPrimaryKeys.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'wikidocs'; 5 | 6 | ALTER TABLE wikidocs_index DROP CONSTRAINT IF EXISTS wikidocs_index_pkey; 7 | -------------------------------------------------------------------------------- /mbdata/sql/wikidocs/DropReplicationTriggers.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'wikidocs'; 5 | 6 | DROP TRIGGER IF EXISTS reptg_wikidocs_index ON wikidocs_index; 7 | -------------------------------------------------------------------------------- /mbdata/sql/wikidocs/DropReplicationTriggers2.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'wikidocs'; 5 | 6 | DROP TRIGGER IF EXISTS reptg2_wikidocs_index ON wikidocs_index; 7 | -------------------------------------------------------------------------------- /mbdata/sql/wikidocs/DropTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \unset ON_ERROR_STOP 3 | 4 | SET search_path = 'wikidocs'; 5 | 6 | DROP TABLE wikidocs_index; 7 | -------------------------------------------------------------------------------- /mbdata/sql/wikidocs/TruncateTables.sql: -------------------------------------------------------------------------------- 1 | -- Automatically generated, do not edit. 2 | \set ON_ERROR_STOP 1 3 | 4 | SET search_path = 'wikidocs'; 5 | 6 | TRUNCATE TABLE wikidocs_index RESTART IDENTITY CASCADE; 7 | -------------------------------------------------------------------------------- /mbdata/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metabrainz/mbdata/648c34e19327fbc12ccfec6f363f456315da1024/mbdata/tests/__init__.py -------------------------------------------------------------------------------- /mbdata/tests/test_tools_genmodels.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from mbdata.tools.genmodels import ( 4 | format_model_name, 5 | parse_sql, 6 | convert_expression_to_python, 7 | ) 8 | 9 | 10 | @pytest.mark.parametrize( 11 | "table_name, model_name", 12 | [ 13 | ('artist', 'Artist'), 14 | ('recording_isrc', 'RecordingISRC'), 15 | ('l_artist_artist', 'LinkArtistArtist'), 16 | ('iso_3166_1', 'ISO31661'), 17 | ] 18 | ) 19 | def test_format_model_name(table_name, model_name): 20 | assert format_model_name(table_name) == model_name 21 | 22 | 23 | def test_parse_create_tables_sql(): 24 | sql = ''' 25 | CREATE TABLE release ( 26 | id SERIAL, -- PK 27 | name VARCHAR NOT NULL 28 | ); 29 | 30 | SET search_path = 'cover_art_archive'; 31 | 32 | CREATE TYPE COVER_ART_TYPE AS ENUM ('front', 'back'); 33 | 34 | CREATE TABLE cover_art ( 35 | id SERIAL, -- PK 36 | release INTEGER NOT NULL, -- references musicbrainz.release.id 37 | type COVER_ART_TYPE 38 | ); 39 | ''' 40 | 41 | tables, types, indexes = parse_sql(sql) 42 | 43 | assert 1 == len(types) 44 | 45 | assert 'cover_art_archive' == types[0].schema 46 | assert 'COVER_ART_TYPE' == types[0].name 47 | assert ['front', 'back'] == types[0].labels 48 | 49 | assert 2 == len(tables) 50 | 51 | assert 'musicbrainz' == tables[0].schema 52 | assert 'release' == tables[0].name 53 | assert 2 == len(tables[0].columns) 54 | assert 'id' == tables[0].columns[0].name 55 | assert 'SERIAL' == tables[0].columns[0].type 56 | assert True is tables[0].columns[0].primary_key 57 | assert None is tables[0].columns[0].foreign_key 58 | assert 'name' == tables[0].columns[1].name 59 | assert 'VARCHAR' == tables[0].columns[1].type 60 | assert False is tables[0].columns[1].primary_key 61 | assert None is tables[0].columns[1].foreign_key 62 | 63 | assert 'cover_art_archive' == tables[1].schema 64 | assert 'cover_art' == tables[1].name 65 | assert 3 == len(tables[1].columns) 66 | assert 'id' == tables[1].columns[0].name 67 | assert 'SERIAL' == tables[1].columns[0].type 68 | assert True is tables[1].columns[0].primary_key 69 | assert None is tables[1].columns[0].foreign_key 70 | assert 'release' == tables[1].columns[1].name 71 | assert 'INTEGER' == tables[1].columns[1].type 72 | assert False is tables[1].columns[1].primary_key 73 | assert 'musicbrainz' == tables[1].columns[1].foreign_key.schema 74 | assert 'release' == tables[1].columns[1].foreign_key.table 75 | assert 'id' == tables[1].columns[1].foreign_key.column 76 | assert 'type' == tables[1].columns[2].name 77 | assert 'COVER_ART_TYPE' == tables[1].columns[2].type 78 | assert False is tables[1].columns[2].primary_key 79 | assert None is tables[1].columns[2].foreign_key 80 | 81 | 82 | def test_expression_to_python_binary_op_compare(): 83 | sql = '''CREATE TABLE table (id SERIAL CHECK (id >= 0));''' 84 | tables, types, indexes = parse_sql(sql) 85 | 86 | assert 1 == len(tables) 87 | assert 1 == len(tables[0].columns) 88 | check = tables[0].columns[0].check_constraint 89 | 90 | assert "sql.literal_column('id') >= sql.text('0')" == convert_expression_to_python(check.text) 91 | 92 | 93 | def test_expression_to_python_is_null(): 94 | sql = '''CREATE TABLE table (id SERIAL CHECK (id IS NULL));''' 95 | tables, types, indexes = parse_sql(sql) 96 | 97 | assert 1 == len(tables) 98 | assert 1 == len(tables[0].columns) 99 | check = tables[0].columns[0].check_constraint 100 | 101 | check.text._pprint_tree() 102 | assert "sql.literal_column('id') == None" == convert_expression_to_python(check.text) 103 | 104 | 105 | def test_expression_to_python_is_not_null(): 106 | sql = '''CREATE TABLE table (id SERIAL CHECK (id IS NOT NULL));''' 107 | tables, types, indexes = parse_sql(sql) 108 | 109 | assert 1 == len(tables) 110 | assert 1 == len(tables[0].columns) 111 | check = tables[0].columns[0].check_constraint 112 | 113 | check.text._pprint_tree() 114 | assert "sql.literal_column('id') != None" == convert_expression_to_python(check.text) 115 | 116 | 117 | def test_expression_to_python_nested_op(): 118 | sql = '''CREATE TABLE table (id SERIAL CHECK (((a IS NOT NULL OR b IS NOT NULL) AND c = TRUE) OR ((a IS NULL AND a IS NULL))));''' 119 | tables, types, indexes = parse_sql(sql) 120 | 121 | assert 1 == len(tables) 122 | assert 1 == len(tables[0].columns) 123 | check = tables[0].columns[0].check_constraint 124 | 125 | expected = ( 126 | "sql.or_((sql.and_((sql.or_(sql.literal_column('a') != None, sql.literal_column('b') != None)), " 127 | "sql.literal_column('c') == sql.true())), ((sql.and_(sql.literal_column('a') == None, sql.literal_column('a') == None))))" 128 | ) 129 | assert expected == convert_expression_to_python(check.text) 130 | 131 | 132 | def test_expression_to_python_special_name(): 133 | sql = '''CREATE TABLE table (length INTEGER CHECK (length IS NULL OR length > 0));''' 134 | tables, types, indexes = parse_sql(sql) 135 | 136 | assert 1 == len(tables) 137 | assert 1 == len(tables[0].columns) 138 | check = tables[0].columns[0].check_constraint 139 | 140 | check.text._pprint_tree() 141 | expected = "sql.or_(sql.text('length') == None, sql.text('length') > sql.text('0'))" 142 | assert expected == convert_expression_to_python(check.text) 143 | 144 | 145 | def test_expression_to_python_special_name_2(): 146 | sql = '''CREATE TABLE table (date DATE NOT NULL CHECK (date >= '2000-01-01'));''' 147 | tables, types, indexes = parse_sql(sql) 148 | 149 | assert 1 == len(tables) 150 | assert 1 == len(tables[0].columns) 151 | check = tables[0].columns[0].check_constraint 152 | 153 | check.text._pprint_tree() 154 | expected = "sql.text('date') >= sql.text(\"'2000-01-01'\")" 155 | assert expected == convert_expression_to_python(check.text) 156 | 157 | 158 | def test_expression_to_python_regex_op(): 159 | sql = '''CREATE TABLE table (id SERIAL CHECK (id ~ E'^\\\\d{11}$'));''' 160 | tables, types, indexes = parse_sql(sql) 161 | 162 | assert 1 == len(tables) 163 | assert 1 == len(tables[0].columns) 164 | check = tables[0].columns[0].check_constraint 165 | 166 | expected = "regexp(sql.literal_column('id'), '^\\d{11}$')" 167 | assert expected == convert_expression_to_python(check.text) 168 | -------------------------------------------------------------------------------- /mbdata/tests/test_utils_sql.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import sys 3 | from six import StringIO 4 | import sqlparse 5 | from sqlparse import tokens as T 6 | from sqlparse.sql import Token, TokenList, Parenthesis 7 | from mbdata.utils.sql import ( 8 | group_parentheses, 9 | parse_statements, 10 | Set, 11 | CreateTable, 12 | CreateType, 13 | CreateIndex, 14 | ) 15 | 16 | 17 | def test_group_parentheses(): 18 | tokens = [ 19 | Token(T.Keyword, 'CREATE'), 20 | Token(T.Whitespace, ' '), 21 | Token(T.Keyword, 'TABLE'), 22 | Token(T.Whitespace, ' '), 23 | Token(T.Name, 'table_name'), 24 | Token(T.Whitespace, ' '), 25 | Token(T.Punctuation, '('), 26 | Token(T.Name, 'id'), 27 | Token(T.Whitespace, ' '), 28 | Token(T.Keyword, 'SERIAL'), 29 | Token(T.Whitespace, ' '), 30 | Token(T.Keyword, 'CHECK'), 31 | Token(T.Punctuation, '('), 32 | Token(T.Name, 'id'), 33 | Token(T.Operator, '='), 34 | Token(T.Number, '0'), 35 | Token(T.Punctuation, ')'), 36 | Token(T.Punctuation, ')'), 37 | Token(T.Punctuation, ';'), 38 | ] 39 | 40 | expected_tokens = TokenList([ 41 | Token(T.Keyword, 'CREATE'), 42 | Token(T.Keyword, 'TABLE'), 43 | Token(T.Name, 'table_name'), 44 | Parenthesis([ 45 | Token(T.Punctuation, '('), 46 | Token(T.Name, 'id'), 47 | Token(T.Keyword, 'SERIAL'), 48 | Token(T.Keyword, 'CHECK'), 49 | Parenthesis([ 50 | Token(T.Punctuation, '('), 51 | Token(T.Name, 'id'), 52 | Token(T.Operator, '='), 53 | Token(T.Number, '0'), 54 | Token(T.Punctuation, ')'), 55 | ]), 56 | Token(T.Punctuation, ')'), 57 | ]), 58 | Token(T.Punctuation, ';'), 59 | ]) 60 | 61 | grouped_tokens = group_parentheses(tokens) 62 | 63 | stdout = sys.stdout 64 | try: 65 | sys.stdout = StringIO() 66 | expected_tokens._pprint_tree() 67 | a = sys.stdout.getvalue() 68 | sys.stdout = StringIO() 69 | grouped_tokens._pprint_tree() 70 | b = sys.stdout.getvalue() 71 | finally: 72 | sys.stdout = stdout 73 | 74 | assert a == b 75 | 76 | 77 | def test_parse_statements(): 78 | sql = ''' 79 | SET search_path = 'cover_art_archive'; 80 | 81 | CREATE TABLE table_name ( 82 | id SERIAL, -- PK 83 | name VARCHAR 84 | ); 85 | 86 | CREATE TYPE FLUENCY AS ENUM ('basic', 'intermediate', 'advanced', 'native'); 87 | ''' 88 | statements = sqlparse.parse(sql) 89 | for statement in statements: 90 | statement._pprint_tree() 91 | print() 92 | statements = parse_statements(statements) 93 | for statement in statements: 94 | print(repr(statement)) 95 | 96 | 97 | def test_set_statement(): 98 | sql = "SET search_path = 'cover_art_archive';" 99 | statement = next(parse_statements(sqlparse.parse(sql))) 100 | 101 | assert isinstance(statement, Set) 102 | assert 'search_path' == statement.get_name() 103 | assert 'cover_art_archive' == statement.get_value() 104 | 105 | 106 | def test_set_statement_without_quotes(): 107 | sql = "SET search_path = cover_art_archive;" 108 | statement = next(parse_statements(sqlparse.parse(sql))) 109 | 110 | assert isinstance(statement, Set) 111 | assert 'search_path' == statement.get_name() 112 | assert 'cover_art_archive' == statement.get_value() 113 | 114 | 115 | def test_set_statement_with_to(): 116 | sql = "SET search_path TO 'cover_art_archive';" 117 | statement = next(parse_statements(sqlparse.parse(sql))) 118 | 119 | assert isinstance(statement, Set) 120 | assert 'search_path' == statement.get_name() 121 | assert 'cover_art_archive' == statement.get_value() 122 | 123 | 124 | def test_create_type_statement(): 125 | sql = "CREATE TYPE FLUENCY AS ENUM ('basic', 'intermediate');" 126 | statement = next(parse_statements(sqlparse.parse(sql))) 127 | 128 | assert isinstance(statement, CreateType) 129 | assert 'FLUENCY' == statement.get_name() 130 | assert ['basic', 'intermediate'] == statement.get_enum_labels() 131 | 132 | 133 | def test_create_table_statement(): 134 | sql = ''' 135 | CREATE TABLE table_name ( 136 | id SERIAL, -- PK 137 | name VARCHAR(100) NOT NULL, 138 | created TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL 139 | ); 140 | ''' 141 | statement = next(parse_statements(sqlparse.parse(sql))) 142 | 143 | assert isinstance(statement, CreateTable) 144 | assert 'table_name' == statement.get_name() 145 | 146 | columns = list(statement.get_columns()) 147 | assert 3 == len(columns) 148 | 149 | column = columns[0] 150 | assert 'id' == column.get_name() 151 | assert 'SERIAL' == column.get_type() 152 | assert None is column.get_default_value() 153 | assert ['-- PK'] == column.get_comments() 154 | assert False is column.is_not_null() 155 | assert None is column.get_check_constraint() 156 | 157 | column = columns[1] 158 | assert 'name' == column.get_name() 159 | assert 'VARCHAR(100)' == column.get_type() 160 | assert None is column.get_default_value() 161 | assert [] == column.get_comments() 162 | assert True is column.is_not_null() 163 | assert None is column.get_check_constraint() 164 | 165 | column = columns[2] 166 | assert 'created' == column.get_name() 167 | assert 'TIMESTAMP WITH TIME ZONE' == column.get_type() 168 | assert 'now()' == column.get_default_value() 169 | assert [] == column.get_comments() 170 | assert True is column.is_not_null() 171 | assert None is column.get_check_constraint() 172 | 173 | 174 | def test_create_table_statement_check_constraint(): 175 | sql = '''CREATE TABLE table_name (column INTEGER(2) NOT NULL DEFAULT 0 CHECK (edits_pending > 0)); ''' 176 | statement = next(parse_statements(sqlparse.parse(sql))) 177 | 178 | assert isinstance(statement, CreateTable) 179 | columns = list(statement.get_columns()) 180 | assert 1 == len(columns) 181 | 182 | column = columns[0] 183 | check = column.get_check_constraint() 184 | assert check 185 | assert None is check.get_name() 186 | assert 'edits_pending>0' == str(check.get_body()) 187 | 188 | 189 | def test_create_table_statement_named_check_constraint(): 190 | sql = '''CREATE TABLE table_name (column INTEGER(2) NOT NULL DEFAULT 0 CONSTRAINT check_column CHECK (edits_pending > 0)); ''' 191 | statement = next(parse_statements(sqlparse.parse(sql))) 192 | 193 | assert isinstance(statement, CreateTable) 194 | columns = list(statement.get_columns()) 195 | assert 1 == len(columns) 196 | 197 | column = columns[0] 198 | check = column.get_check_constraint() 199 | assert check 200 | assert 'check_column' == check.get_name() 201 | assert 'edits_pending>0' == str(check.get_body()) 202 | 203 | 204 | def test_create_index(): 205 | sql = '''CREATE INDEX statistic_name ON statistic (name); ''' 206 | statement = next(parse_statements(sqlparse.parse(sql))) 207 | 208 | assert isinstance(statement, CreateIndex) 209 | assert 'statistic_name' == statement.get_name() 210 | assert 'statistic' == statement.get_table() 211 | assert ['name'] == statement.get_columns() 212 | assert not statement.is_unique() 213 | 214 | 215 | def test_create_unique_index(): 216 | sql = '''CREATE UNIQUE INDEX statistic_name_date_collected ON statistic (name, date_collected); ''' 217 | statement = next(parse_statements(sqlparse.parse(sql))) 218 | 219 | statement._pprint_tree() 220 | 221 | assert isinstance(statement, CreateIndex) 222 | assert 'statistic_name_date_collected' == statement.get_name() 223 | assert 'statistic' == statement.get_table() 224 | assert ['name', 'date_collected'] == statement.get_columns() 225 | assert statement.is_unique() 226 | -------------------------------------------------------------------------------- /mbdata/tools/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | -------------------------------------------------------------------------------- /mbdata/tools/dump_sample_data.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import print_function 4 | import sys 5 | import argparse 6 | import datetime 7 | import re 8 | import unicodedata 9 | from sqlalchemy import create_engine, inspect 10 | from sqlalchemy.orm import sessionmaker 11 | from sqlalchemy.orm.session import object_session 12 | from sqlalchemy.orm.collections import InstrumentedList 13 | from mbdata.models import ( 14 | Area, 15 | Artist, 16 | Label, 17 | LinkAreaArea, 18 | Place, 19 | Recording, 20 | Release, 21 | ReleaseGroup, 22 | Work, 23 | URL, 24 | ) 25 | from mbdata.utils.models import query_links 26 | from typing import Dict, Set 27 | 28 | 29 | RELEASE_GIDS = [ 30 | '89b1b3ca-07cd-4f67-b9a7-3a3ba86d7149', 31 | '7643ee96-fe19-4b76-aa9a-e8af7d0e9d73', 32 | ] 33 | 34 | PLACE_GIDS = [ 35 | 'bd55aeb7-19d1-4607-a500-14b8479d3fed', # Abbey Road Studios 36 | ] 37 | 38 | LABEL_GIDS = [ 39 | 'ecc049d0-88a6-4806-a5b7-0f1367a7d6e1', # Studio Ghibli 40 | ] 41 | 42 | 43 | counters = {} # type: Dict[str, int] 44 | in_progress = set() # type: Set[str] 45 | models = set() # type: Set[str] 46 | 47 | 48 | _unaccent_dict = {u'Æ': u'AE', u'æ': u'ae', u'Œ': u'OE', u'œ': u'oe', u'ß': 'ss'} 49 | _re_latin_letter = re.compile(r"^(LATIN [A-Z]+ LETTER [A-Z]+) WITH") 50 | 51 | 52 | def unaccent(string): 53 | result = [] 54 | for char in string: 55 | if char in _unaccent_dict: 56 | char = _unaccent_dict[char] 57 | else: 58 | try: 59 | name = unicodedata.name(char) 60 | match = _re_latin_letter.search(name) 61 | if match: 62 | char = unicodedata.lookup(match.group(1)) 63 | except Exception: 64 | pass 65 | result.append(char) 66 | return "".join(result) 67 | 68 | 69 | def name_to_variable(name): 70 | return re.sub('_+', '_', re.sub('[^0-9a-z]', '_', unaccent(name).lower())).strip('_') 71 | 72 | 73 | def generate_name(obj): 74 | name = obj.__class__.__name__.lower() 75 | if hasattr(obj, 'name') and obj.name: 76 | suffix = name_to_variable(obj.name) 77 | if not suffix and hasattr(obj, 'sort_name') and obj.sort_name: 78 | suffix = name_to_variable(obj.sort_name) 79 | if suffix: 80 | name = '{0}_{1}'.format(name, suffix) 81 | elif name not in counters: 82 | counters[name] = 0 83 | 84 | if name in counters: 85 | counters[name] += 1 86 | name += '_{0}'.format(counters[name]) 87 | else: 88 | counters[name] = 0 89 | 90 | return name 91 | 92 | 93 | def dump_value(value): 94 | if isinstance(value, datetime.datetime): 95 | value = value.replace(tzinfo=None) 96 | return repr(value) 97 | 98 | 99 | def find_name(output, names, obj): 100 | state = inspect(obj) 101 | mapper = state.mapper 102 | 103 | key = state.identity_key 104 | if key in in_progress: 105 | return None 106 | 107 | if key in names: 108 | return names[key] 109 | 110 | in_progress.add(key) 111 | models.add(obj.__class__.__name__) 112 | 113 | name = generate_name(obj) 114 | 115 | code = [] 116 | code.append('{0} = {1}()'.format(name, obj.__class__.__name__)) 117 | 118 | for attr in mapper.column_attrs: 119 | if sum([len(column.foreign_keys) for column in attr.columns]): 120 | continue 121 | value = getattr(obj, attr.key) 122 | if value is None: 123 | continue 124 | code.append('{0}.{1} = {2}'.format(name, attr.key, dump_value(value))) 125 | 126 | for attr in sorted(mapper.relationships, key=lambda attr: attr.key): 127 | value = getattr(obj, attr.key, None) 128 | if value is None: 129 | continue 130 | if isinstance(value, InstrumentedList): 131 | value_names = [] 132 | for item in value: 133 | value_name = find_name(output, names, item) 134 | if value_name is not None: 135 | value_names.append(value_name) 136 | if value_names: 137 | code.append('{0}.{1} = ['.format(name, attr.key)) 138 | for value_name in value_names: 139 | code.append(' {0},'.format(value_name)) 140 | code.append(']') 141 | else: 142 | value_name = find_name(output, names, value) 143 | if value_name is not None: 144 | code.append('{0}.{1} = {2}'.format(name, attr.key, value_name)) 145 | 146 | code.append('session.add({0})'.format(name)) 147 | 148 | output.append('\n'.join(code)) 149 | 150 | names[key] = name 151 | in_progress.remove(key) 152 | 153 | # special case -- dump parent relationships for areas 154 | if isinstance(obj, Area): 155 | session = object_session(obj) 156 | query = session.query(LinkAreaArea).\ 157 | filter(LinkAreaArea.entity1_id == obj.id) 158 | for sub_obj in query: 159 | find_name(output, names, sub_obj) 160 | 161 | # special case -- dump artist/place/label/url relationships for "music" entities 162 | if isinstance(obj, (ReleaseGroup, Release, Recording, Work)): 163 | for target_model in (Artist, Place, Label, URL): 164 | for sub_obj in query_links(obj, target_model): 165 | find_name(output, names, sub_obj) 166 | 167 | # special case -- dump work relationships for recordings and works 168 | if isinstance(obj, (Recording, Work)): 169 | for sub_obj in query_links(obj, Work): 170 | find_name(output, names, sub_obj) 171 | 172 | return name 173 | 174 | 175 | def dump_sample_data(session): 176 | output = [] 177 | names = {} 178 | 179 | queries = [ 180 | session.query(Release).filter(Release.gid.in_(RELEASE_GIDS)), 181 | session.query(Place).filter(Place.gid.in_(PLACE_GIDS)), 182 | session.query(Label).filter(Label.gid.in_(LABEL_GIDS)), 183 | ] 184 | for query in queries: 185 | for item in query: 186 | find_name(output, names, item) 187 | 188 | print('import datetime') 189 | models_to_import = list(sorted(models)) 190 | while models_to_import: 191 | print('from mbdata.models import {0}'.format(', '.join(models_to_import[:5]))) 192 | models_to_import = models_to_import[5:] 193 | print() 194 | print() 195 | 196 | print('def create_sample_data(session):') 197 | 198 | for line in '\n\n'.join(output).splitlines(): 199 | if not line: 200 | print() 201 | else: 202 | print(' ' + line) 203 | 204 | print() 205 | print(' session.commit()') 206 | 207 | 208 | if __name__ == '__main__': 209 | parser = argparse.ArgumentParser() 210 | parser.add_argument('-d', dest='db_uri') 211 | args = parser.parse_args() 212 | 213 | engine = create_engine(args.db_uri) 214 | Session = sessionmaker(bind=engine) 215 | session = Session() 216 | 217 | dump_sample_data(session) 218 | -------------------------------------------------------------------------------- /mbdata/types.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | import re 5 | from sqlalchemy.ext.compiler import compiles 6 | from sqlalchemy.types import UserDefinedType 7 | from sqlalchemy.sql.expression import ClauseElement, TextClause 8 | try: 9 | from sqlalchemy.dialects.postgresql import UUID, SMALLINT, BIGINT, JSONB 10 | except ImportError: 11 | from sqlalchemy.dialects.postgres import UUID, SMALLINT, BIGINT, JSONB 12 | 13 | 14 | @compiles(UUID, 'sqlite') 15 | def visit_uuid_sqlite(element, compiler, **kwargs): 16 | return 'CHAR(32)' 17 | 18 | 19 | # XXX this should really serialize/deserialize to JSON 20 | @compiles(JSONB, 'sqlite') 21 | def visit_jsonb_sqlite(element, compiler, **kwargs): 22 | return 'TEXT' 23 | 24 | 25 | class regexp(ClauseElement): 26 | def __init__(self, column, pattern): 27 | self.column = column 28 | self.pattern = TextClause(pattern) 29 | 30 | 31 | @compiles(regexp) 32 | def visit_regexp(element, compiler, **kwargs): 33 | return '{0} REGEXP {1}'.format( 34 | compiler.process(element.column), 35 | compiler.process(element.pattern)) 36 | 37 | 38 | @compiles(regexp, 'postgresql') 39 | def visit_regexp_postgresql(element, compiler, **kwargs): 40 | return '{0} ~ {1}'.format( 41 | compiler.process(element.column), 42 | compiler.process(element.pattern)) 43 | 44 | 45 | class PartialDate(object): 46 | 47 | __slots__ = ('year', 'month', 'day') 48 | 49 | def __init__(self, year=None, month=None, day=None): 50 | self.year = year 51 | self.month = month 52 | self.day = day 53 | 54 | def __composite_values__(self): 55 | return self.year, self.month, self.day 56 | 57 | def __iter__(self): 58 | yield self.year 59 | yield self.month 60 | yield self.day 61 | 62 | def __repr__(self): 63 | return "{0.__class__.__name__}(year={0.year}, month={0.month}, day={0.day})".format(self) 64 | 65 | def __eq__(self, other): 66 | return isinstance(other, PartialDate) and \ 67 | other.year == self.year and \ 68 | other.month == self.month and \ 69 | other.day == self.day 70 | 71 | def __hash__(self): 72 | return hash((self.year, self.month, self.day)) 73 | 74 | def __ne__(self, other): 75 | return not self.__eq__(other) 76 | 77 | def __bool__(self): 78 | return bool(self.year or self.month or self.day) 79 | 80 | __nonzero__ = __bool__ 81 | 82 | 83 | class Point(UserDefinedType): 84 | 85 | # pylint: disable=W0223 86 | # pylint: disable=R0201 87 | 88 | def get_col_spec(self): 89 | return 'POINT' 90 | 91 | def bind_processor(self, dialect): 92 | def process(value): 93 | if value is None: 94 | return None 95 | return '({0},{1})'.format(value[0], value[1]) 96 | return process 97 | 98 | def result_processor(self, dialect, coltype): 99 | def process(value): 100 | if value is None: 101 | return None 102 | match = re.match(r'\((-?[0-9.]+),(-?[0-9.]+)\)', value) 103 | return tuple([float(x) for x in match.groups()]) 104 | return process 105 | 106 | 107 | class Cube(UserDefinedType): 108 | 109 | # pylint: disable=W0223 110 | # pylint: disable=R0201 111 | 112 | def get_col_spec(self): 113 | return 'CUBE' 114 | 115 | def bind_processor(self, dialect): 116 | def process(value): 117 | if value is None: 118 | return None 119 | return value 120 | return process 121 | 122 | def result_processor(self, dialect, coltype): 123 | def process(value): 124 | if value is None: 125 | return None 126 | return value 127 | return process 128 | 129 | -------------------------------------------------------------------------------- /mbdata/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Lukas Lalinsky 2 | # Distributed under the MIT license, see the LICENSE file for details. 3 | 4 | NO_SCHEMAS = { 5 | 'musicbrainz': None, 6 | 'cover_art_archive': None, 7 | 'wikidocs': None, 8 | 'statistics': None, 9 | 'documentation': None, 10 | } 11 | 12 | SINGLE_MUSICBRAINZ_SCHEMA = { 13 | 'musicbrainz': 'musicbrainz', 14 | 'cover_art_archive': 'musicbrainz', 15 | 'wikidocs': 'musicbrainz', 16 | 'statistics': 'musicbrainz', 17 | 'documentation': 'musicbrainz', 18 | } 19 | 20 | 21 | def patch_model_schemas(mapping): 22 | """Update mbdata.models to use different schema names 23 | 24 | The function accepts a dictionary with schema name mapping 25 | and updates the schema for all MusicBrainz tables. 26 | 27 | If you want to use the default schema: 28 | 29 | >>> patch_model_schemas(NO_SCHEMAS) 30 | 31 | If you have just one 'musicbrainz' schema: 32 | 33 | >>> patch_model_schemas(SINGLE_MUSICBRAINZ_SCHEMA) 34 | 35 | """ 36 | from mbdata.models import Base 37 | 38 | for table in Base.metadata.sorted_tables: 39 | if table.schema is None: 40 | continue 41 | table.schema = mapping.get(table.schema, table.schema) 42 | 43 | 44 | def get_something_by_gid(query, redirect_model, gid): 45 | artist = query.filter_by(gid=gid).first() 46 | if artist is None: 47 | subquery = query.session.query(redirect_model.redirect_id).\ 48 | filter_by(gid=gid) 49 | artist = query.filter(redirect_model.redirect.property.primaryjoin.left.in_(subquery)).first() 50 | return artist 51 | 52 | -------------------------------------------------------------------------------- /mbdata/utils/models.py: -------------------------------------------------------------------------------- 1 | from mbdata import models 2 | from sqlalchemy import inspect 3 | from sqlalchemy.orm.session import object_session 4 | 5 | 6 | ENTITY_TYPES = { 7 | 'artist': models.Artist, 8 | 'label': models.Label, 9 | 'place': models.Place, 10 | 'release_group': models.ReleaseGroup, 11 | 'release': models.Release, 12 | 'url': models.URL, 13 | 'work': models.Work, 14 | } 15 | 16 | 17 | def get_entity_type_model(type): 18 | return ENTITY_TYPES[type] 19 | 20 | 21 | def get_link_model(entity0, entity1): 22 | names = sorted([entity0.__name__, entity1.__name__]) 23 | assert all(hasattr(models, name) for name in names) 24 | return getattr(models, 'Link{0}{1}'.format(*names)) 25 | 26 | 27 | def get_link_target(link, source): 28 | model = inspect(link).mapper.class_ 29 | source_model = inspect(source).mapper.class_ 30 | 31 | if source_model != model.entity0.property.mapper.class_: 32 | return link.entity0 33 | 34 | if source_model != model.entity1.property.mapper.class_: 35 | return link.entity1 36 | 37 | if source.id != link.entity0_id: 38 | return link.entity0 39 | 40 | if source.id != link.entity1_id: 41 | return link.entity1 42 | 43 | 44 | def query_links(obj, target_model): 45 | session = object_session(obj) 46 | model = get_link_model(inspect(obj).mapper.class_, target_model) 47 | query = session.query(model) 48 | 49 | if isinstance(obj, model.entity0.property.mapper.class_): 50 | query = query.filter_by(entity0=obj) 51 | 52 | if isinstance(obj, model.entity1.property.mapper.class_): 53 | query = query.filter_by(entity1=obj) 54 | 55 | return query 56 | 57 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "mbdata" 3 | description = "MusicBrainz Database Tools" 4 | readme = "README.rst" 5 | authors = [ 6 | { name = "MetaBrainz Foundation", email = "support@metabrainz.org"}, 7 | { name = "Lukáš Lalinský", email = ""}, 8 | ] 9 | license = "MIT" 10 | dynamic = ["version"] 11 | 12 | [tool.poetry] 13 | version = "0.0.0" 14 | 15 | [tool.poetry.dependencies] 16 | python = "^3.7" 17 | SQLAlchemy = {version = "^1.4.29", optional = true} 18 | lxml = {version = "^4.9.1", optional = true} 19 | six = "^1.16.0" 20 | 21 | [tool.poetry.group.dev.dependencies] 22 | flake8 = "^5.0.0" 23 | psycopg2 = "^2.9.2" 24 | sqlparse = "^0.4.4" 25 | pytest = "^7.2.0" 26 | mypy = "^0.991" 27 | types-six = "^1.16.21" 28 | types-psycopg2 = "^2.9.21" 29 | 30 | [tool.poetry.extras] 31 | search = ["lxml"] 32 | models = ["SQLAlchemy"] 33 | 34 | [tool.poetry-dynamic-versioning] 35 | enable = true 36 | 37 | [build-system] 38 | requires = ["poetry-core>=2.0.0,<3.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"] 39 | build-backend = "poetry_dynamic_versioning.backend" 40 | -------------------------------------------------------------------------------- /scripts/create_sample_db.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | 7 | import argparse 8 | from sqlalchemy import create_engine 9 | from sqlalchemy.orm import sessionmaker 10 | 11 | import mbdata.config 12 | mbdata.config.configure(schema=None) 13 | mbdata.config.freeze() 14 | 15 | from mbdata.sample_data import create_sample_data # noqa: E402 16 | from mbdata.models import Base # noqa: E402 17 | 18 | 19 | parser = argparse.ArgumentParser(add_help=True, 20 | description='Create a small sample database.') 21 | parser.add_argument('file', help='path of the db-file') 22 | parser.add_argument('--overwrite', '-o', action='store_true', 23 | default=False, help='silently overwrite db-file') 24 | args = parser.parse_args() 25 | 26 | if os.path.isfile(args.file): 27 | if args.overwrite: 28 | os.remove(args.file) 29 | else: 30 | print("Error: Database file already exists. You may want to use the '-o' flag.", file=sys.stderr) 31 | sys.exit(1) 32 | 33 | engine = create_engine('sqlite:///' + args.file) 34 | Base.metadata.create_all(engine) 35 | 36 | Session = sessionmaker(bind=engine) 37 | session = Session() 38 | create_sample_data(session) 39 | -------------------------------------------------------------------------------- /scripts/create_solr_home.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import argparse 5 | 6 | from mbdata.search import create_solr_home 7 | 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument('-d', '--directory', required=True) 10 | args = parser.parse_args() 11 | 12 | # TODO allow custom core name 13 | # TODO allow creating just a core in an existing Solr home 14 | 15 | create_solr_home(args.directory) 16 | print(open(os.path.join(args.directory, 'README.txt')).read()) 17 | 18 | -------------------------------------------------------------------------------- /scripts/dump_sample_data.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | python -m mbdata.tools.dump_sample_data -d "$1" >mbdata/sample_data.py 4 | 5 | -------------------------------------------------------------------------------- /scripts/export_solr_triggers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | 5 | from sqlalchemy import create_engine 6 | from sqlalchemy.orm import sessionmaker 7 | 8 | import settings 9 | from mbdata.search import export_triggers 10 | 11 | 12 | parser = argparse.ArgumentParser() 13 | args = parser.parse_args() 14 | 15 | engine = create_engine(settings.DATABASE_URI, echo=False) 16 | Session = sessionmaker(bind=engine) 17 | db = Session() 18 | 19 | export_triggers(db) 20 | 21 | -------------------------------------------------------------------------------- /scripts/update_models.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | python -m mbdata.tools.genmodels \ 4 | mbdata/sql/CreateTypes.sql \ 5 | mbdata/sql/CreateTables.sql \ 6 | mbdata/sql/caa/CreateTables.sql \ 7 | mbdata/sql/wikidocs/CreateTables.sql \ 8 | mbdata/sql/documentation/CreateTables.sql \ 9 | mbdata/sql/statistics/CreateTables.sql \ 10 | >mbdata/models.py 11 | -------------------------------------------------------------------------------- /scripts/update_sql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd $(dirname $0)/../mbdata 4 | 5 | GIT_TARGET="${1:-v-2024-05-13-schema-change}" 6 | 7 | rm -rf sql 8 | 9 | rm -rf /tmp/mbserver-clone 10 | mkdir /tmp/mbserver-clone 11 | 12 | curl -L -o "/tmp/mbserver-clone/$GIT_TARGET.tar.gz" "https://github.com/metabrainz/musicbrainz-server/archive/$GIT_TARGET.tar.gz" 13 | tar -x -f "/tmp/mbserver-clone/$GIT_TARGET.tar.gz" --strip-components=2 --wildcards "musicbrainz-server-$GIT_TARGET/admin/sql/*" 14 | rm -rf /tmp/mbserver-clone 15 | 16 | echo '\set ON_ERROR_STOP 1' >sql/CreateCollateIndexes.sql 17 | echo 'BEGIN;' >>sql/CreateCollateIndexes.sql 18 | grep _collate sql/CreateIndexes.sql >> sql/CreateCollateIndexes.sql 19 | echo 'COMMIT;' >>sql/CreateCollateIndexes.sql 20 | 21 | echo '\set ON_ERROR_STOP 1' >sql/DropCollateIndexes.sql 22 | grep _collate sql/DropIndexes.sql >> sql/DropCollateIndexes.sql 23 | 24 | mv sql/CreateIndexes.sql sql/CreateIndexes.sql.remove 25 | grep -v _collate sql/CreateIndexes.sql.remove >> sql/CreateIndexes.sql 26 | rm sql/CreateIndexes.sql.remove 27 | 28 | mv sql/DropIndexes.sql sql/DropIndexes.sql.remove 29 | grep -v _collate sql/DropIndexes.sql.remove >> sql/DropIndexes.sql 30 | rm sql/DropIndexes.sql.remove 31 | 32 | rm -rf sql/updates 33 | -------------------------------------------------------------------------------- /scripts/upload_to_pypi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ex 4 | 5 | rm -rf dist/ 6 | python setup.py sdist 7 | twine upload dist/mbdata-*.tar.gz 8 | -------------------------------------------------------------------------------- /settings.py.sample: -------------------------------------------------------------------------------- 1 | DATABASE_URI = 'postgresql://musicbrainz:FIXME@127.0.0.1/musicbrainz' 2 | 3 | SOLR_URI = 'http://127.0.0.1:8983/solr/musicbrainz' 4 | 5 | --------------------------------------------------------------------------------