mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 08:56:17 +00:00
Use hex-encoded string for id instead of bytes on DBMSs that don't provide native UUID support
Closes #241
This commit is contained in:
parent
ba1fbf4b73
commit
4bbd7e94b0
@ -15,7 +15,6 @@ from datetime import datetime
|
|||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from peewee import (
|
from peewee import (
|
||||||
AutoField,
|
AutoField,
|
||||||
BinaryUUIDField,
|
|
||||||
BlobField,
|
BlobField,
|
||||||
BooleanField,
|
BooleanField,
|
||||||
CharField,
|
CharField,
|
||||||
@ -24,6 +23,7 @@ from peewee import (
|
|||||||
ForeignKeyField,
|
ForeignKeyField,
|
||||||
IntegerField,
|
IntegerField,
|
||||||
TextField,
|
TextField,
|
||||||
|
UUIDField,
|
||||||
)
|
)
|
||||||
from peewee import CompositeKey, DatabaseProxy, Model, MySQLDatabase
|
from peewee import CompositeKey, DatabaseProxy, Model, MySQLDatabase
|
||||||
from peewee import fn
|
from peewee import fn
|
||||||
@ -31,7 +31,7 @@ from playhouse.db_url import parseresult_to_dict, schemes
|
|||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
SCHEMA_VERSION = "20200607"
|
SCHEMA_VERSION = "20230111"
|
||||||
|
|
||||||
|
|
||||||
def now():
|
def now():
|
||||||
@ -45,7 +45,7 @@ def random():
|
|||||||
|
|
||||||
|
|
||||||
def PrimaryKeyField(**kwargs):
|
def PrimaryKeyField(**kwargs):
|
||||||
return BinaryUUIDField(primary_key=True, default=uuid4, **kwargs)
|
return UUIDField(primary_key=True, default=uuid4, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
db = DatabaseProxy()
|
db = DatabaseProxy()
|
||||||
|
75
supysonic/schema/migration/mysql/20230111.py
Normal file
75
supysonic/schema/migration/mysql/20230111.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# This file is part of Supysonic.
|
||||||
|
# Supysonic is a Python implementation of the Subsonic server API.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2023 Alban 'spl0k' Féron
|
||||||
|
#
|
||||||
|
# Distributed under terms of the GNU AGPLv3 license.
|
||||||
|
|
||||||
|
# Converts ids from binary data to hex-encoded strings
|
||||||
|
|
||||||
|
try:
|
||||||
|
import MySQLdb as provider
|
||||||
|
except ImportError:
|
||||||
|
import pymysql as provider
|
||||||
|
|
||||||
|
from uuid import UUID
|
||||||
|
from warnings import filterwarnings
|
||||||
|
|
||||||
|
|
||||||
|
def process_table(connection, table, fields, nullable_fields=()):
|
||||||
|
to_update = {field: set() for field in fields + nullable_fields}
|
||||||
|
|
||||||
|
c = connection.cursor()
|
||||||
|
c.execute("SELECT {1} FROM {0}".format(table, ",".join(fields + nullable_fields)))
|
||||||
|
for row in c:
|
||||||
|
for field, value in zip(fields + nullable_fields, row):
|
||||||
|
if value is None or not isinstance(value, bytes):
|
||||||
|
continue
|
||||||
|
to_update[field].add(value)
|
||||||
|
|
||||||
|
for field in fields:
|
||||||
|
sql = "ALTER TABLE {} MODIFY {} BINARY(32) NOT NULL".format(table, field)
|
||||||
|
c.execute(sql)
|
||||||
|
for field in nullable_fields:
|
||||||
|
sql = "ALTER TABLE {} MODIFY {} BINARY(32)".format(table, field)
|
||||||
|
c.execute(sql)
|
||||||
|
for field, values in to_update.items():
|
||||||
|
if not values:
|
||||||
|
continue
|
||||||
|
sql = "UPDATE {0} SET {1}=%s WHERE {1}=%s".format(table, field)
|
||||||
|
c.executemany(
|
||||||
|
sql, map(lambda v: (UUID(bytes=v).hex, v + (b"\x00" * 16)), values)
|
||||||
|
)
|
||||||
|
for field in fields:
|
||||||
|
sql = "ALTER TABLE {} MODIFY {} CHAR(32) NOT NULL".format(table, field)
|
||||||
|
c.execute(sql)
|
||||||
|
for field in nullable_fields:
|
||||||
|
sql = "ALTER TABLE {} MODIFY {} CHAR(32)".format(table, field)
|
||||||
|
c.execute(sql)
|
||||||
|
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def apply(args):
|
||||||
|
filterwarnings("ignore", category=provider.Warning)
|
||||||
|
|
||||||
|
conn = provider.connect(**args)
|
||||||
|
conn.cursor().execute("SET FOREIGN_KEY_CHECKS = 0")
|
||||||
|
|
||||||
|
process_table(conn, "artist", ("id",))
|
||||||
|
process_table(conn, "album", ("id", "artist_id"))
|
||||||
|
process_table(conn, "track", ("id", "album_id", "artist_id"))
|
||||||
|
process_table(conn, "user", ("id",), ("last_play_id",))
|
||||||
|
process_table(conn, "client_prefs", ("user_id",))
|
||||||
|
process_table(conn, "starred_folder", ("user_id",))
|
||||||
|
process_table(conn, "starred_artist", ("user_id", "starred_id"))
|
||||||
|
process_table(conn, "starred_album", ("user_id", "starred_id"))
|
||||||
|
process_table(conn, "starred_track", ("user_id", "starred_id"))
|
||||||
|
process_table(conn, "rating_folder", ("user_id",))
|
||||||
|
process_table(conn, "rating_track", ("user_id", "rated_id"))
|
||||||
|
process_table(conn, "chat_message", ("id", "user_id"))
|
||||||
|
process_table(conn, "playlist", ("id", "user_id"))
|
||||||
|
process_table(conn, "radio_station", ("id",))
|
||||||
|
|
||||||
|
conn.cursor().execute("SET FOREIGN_KEY_CHECKS = 1")
|
||||||
|
conn.close()
|
50
supysonic/schema/migration/sqlite/20230111.py
Normal file
50
supysonic/schema/migration/sqlite/20230111.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# This file is part of Supysonic.
|
||||||
|
# Supysonic is a Python implementation of the Subsonic server API.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2023 Alban 'spl0k' Féron
|
||||||
|
#
|
||||||
|
# Distributed under terms of the GNU AGPLv3 license.
|
||||||
|
|
||||||
|
# Converts ids from binary data to hex-encoded strings
|
||||||
|
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
|
||||||
|
def process_table(connection, table, fields):
|
||||||
|
to_update = {field: set() for field in fields}
|
||||||
|
|
||||||
|
c = connection.cursor()
|
||||||
|
for row in c.execute("SELECT {1} FROM {0}".format(table, ",".join(fields))):
|
||||||
|
for field, value in zip(fields, row):
|
||||||
|
if value is None or not isinstance(value, bytes):
|
||||||
|
continue
|
||||||
|
to_update[field].add(value)
|
||||||
|
|
||||||
|
for field, values in to_update.items():
|
||||||
|
sql = "UPDATE {0} SET {1}=? WHERE {1}=?".format(table, field)
|
||||||
|
c.executemany(sql, map(lambda v: (UUID(bytes=v).hex, v), values))
|
||||||
|
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def apply(args):
|
||||||
|
file = args.pop("database")
|
||||||
|
with sqlite3.connect(file, **args) as conn:
|
||||||
|
conn.cursor().execute("PRAGMA foreign_keys = OFF")
|
||||||
|
|
||||||
|
process_table(conn, "artist", ("id",))
|
||||||
|
process_table(conn, "album", ("id", "artist_id"))
|
||||||
|
process_table(conn, "track", ("id", "album_id", "artist_id"))
|
||||||
|
process_table(conn, "user", ("id", "last_play_id"))
|
||||||
|
process_table(conn, "client_prefs", ("user_id",))
|
||||||
|
process_table(conn, "starred_folder", ("user_id",))
|
||||||
|
process_table(conn, "starred_artist", ("user_id", "starred_id"))
|
||||||
|
process_table(conn, "starred_album", ("user_id", "starred_id"))
|
||||||
|
process_table(conn, "starred_track", ("user_id", "starred_id"))
|
||||||
|
process_table(conn, "rating_folder", ("user_id",))
|
||||||
|
process_table(conn, "rating_track", ("user_id", "rated_id"))
|
||||||
|
process_table(conn, "chat_message", ("id", "user_id"))
|
||||||
|
process_table(conn, "playlist", ("id", "user_id"))
|
||||||
|
process_table(conn, "radio_station", ("id",))
|
@ -12,19 +12,19 @@ CREATE TABLE IF NOT EXISTS folder (
|
|||||||
CREATE INDEX index_folder_parent_id_fk ON folder(parent_id);
|
CREATE INDEX index_folder_parent_id_fk ON folder(parent_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS artist (
|
CREATE TABLE IF NOT EXISTS artist (
|
||||||
id BINARY(16) PRIMARY KEY,
|
id CHAR(32) PRIMARY KEY,
|
||||||
name VARCHAR(256) NOT NULL
|
name VARCHAR(256) NOT NULL
|
||||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS album (
|
CREATE TABLE IF NOT EXISTS album (
|
||||||
id BINARY(16) PRIMARY KEY,
|
id CHAR(32) PRIMARY KEY,
|
||||||
name VARCHAR(256) NOT NULL,
|
name VARCHAR(256) NOT NULL,
|
||||||
artist_id BINARY(16) NOT NULL REFERENCES artist(id)
|
artist_id CHAR(32) NOT NULL REFERENCES artist(id)
|
||||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
CREATE INDEX index_album_artist_id_fk ON album(artist_id);
|
CREATE INDEX index_album_artist_id_fk ON album(artist_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS track (
|
CREATE TABLE IF NOT EXISTS track (
|
||||||
id BINARY(16) PRIMARY KEY,
|
id CHAR(32) PRIMARY KEY,
|
||||||
disc INTEGER NOT NULL,
|
disc INTEGER NOT NULL,
|
||||||
number INTEGER NOT NULL,
|
number INTEGER NOT NULL,
|
||||||
title VARCHAR(256) NOT NULL,
|
title VARCHAR(256) NOT NULL,
|
||||||
@ -32,8 +32,8 @@ CREATE TABLE IF NOT EXISTS track (
|
|||||||
genre VARCHAR(256),
|
genre VARCHAR(256),
|
||||||
duration INTEGER NOT NULL,
|
duration INTEGER NOT NULL,
|
||||||
has_art BOOLEAN NOT NULL DEFAULT false,
|
has_art BOOLEAN NOT NULL DEFAULT false,
|
||||||
album_id BINARY(16) NOT NULL REFERENCES album(id),
|
album_id CHAR(32) NOT NULL REFERENCES album(id),
|
||||||
artist_id BINARY(16) NOT NULL REFERENCES artist(id),
|
artist_id CHAR(32) NOT NULL REFERENCES artist(id),
|
||||||
bitrate INTEGER NOT NULL,
|
bitrate INTEGER NOT NULL,
|
||||||
path VARCHAR(4096) NOT NULL,
|
path VARCHAR(4096) NOT NULL,
|
||||||
path_hash BINARY(20) UNIQUE NOT NULL,
|
path_hash BINARY(20) UNIQUE NOT NULL,
|
||||||
@ -50,7 +50,7 @@ CREATE INDEX index_track_folder_id_fk ON track(folder_id);
|
|||||||
CREATE INDEX index_track_root_folder_id_fk ON track(root_folder_id);
|
CREATE INDEX index_track_root_folder_id_fk ON track(root_folder_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS user (
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
id BINARY(16) PRIMARY KEY,
|
id CHAR(32) PRIMARY KEY,
|
||||||
name VARCHAR(64) NOT NULL,
|
name VARCHAR(64) NOT NULL,
|
||||||
mail VARCHAR(256),
|
mail VARCHAR(256),
|
||||||
password CHAR(40) NOT NULL,
|
password CHAR(40) NOT NULL,
|
||||||
@ -59,13 +59,13 @@ CREATE TABLE IF NOT EXISTS user (
|
|||||||
jukebox BOOLEAN NOT NULL,
|
jukebox BOOLEAN NOT NULL,
|
||||||
lastfm_session CHAR(32),
|
lastfm_session CHAR(32),
|
||||||
lastfm_status BOOLEAN NOT NULL,
|
lastfm_status BOOLEAN NOT NULL,
|
||||||
last_play_id BINARY(16) REFERENCES track(id),
|
last_play_id CHAR(32) REFERENCES track(id),
|
||||||
last_play_date DATETIME
|
last_play_date DATETIME
|
||||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
CREATE INDEX index_user_last_play_id_fk ON user(last_play_id);
|
CREATE INDEX index_user_last_play_id_fk ON user(last_play_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS client_prefs (
|
CREATE TABLE IF NOT EXISTS client_prefs (
|
||||||
user_id BINARY(16) NOT NULL,
|
user_id CHAR(32) NOT NULL,
|
||||||
client_name VARCHAR(32) NOT NULL,
|
client_name VARCHAR(32) NOT NULL,
|
||||||
format VARCHAR(8),
|
format VARCHAR(8),
|
||||||
bitrate INTEGER,
|
bitrate INTEGER,
|
||||||
@ -73,7 +73,7 @@ CREATE TABLE IF NOT EXISTS client_prefs (
|
|||||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS starred_folder (
|
CREATE TABLE IF NOT EXISTS starred_folder (
|
||||||
user_id BINARY(16) NOT NULL REFERENCES user(id),
|
user_id CHAR(32) NOT NULL REFERENCES user(id),
|
||||||
starred_id INTEGER NOT NULL REFERENCES folder(id),
|
starred_id INTEGER NOT NULL REFERENCES folder(id),
|
||||||
date DATETIME NOT NULL,
|
date DATETIME NOT NULL,
|
||||||
PRIMARY KEY (user_id, starred_id)
|
PRIMARY KEY (user_id, starred_id)
|
||||||
@ -82,8 +82,8 @@ CREATE INDEX index_starred_folder_user_id_fk ON starred_folder(user_id);
|
|||||||
CREATE INDEX index_starred_folder_starred_id_fk ON starred_folder(starred_id);
|
CREATE INDEX index_starred_folder_starred_id_fk ON starred_folder(starred_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS starred_artist (
|
CREATE TABLE IF NOT EXISTS starred_artist (
|
||||||
user_id BINARY(16) NOT NULL REFERENCES user(id),
|
user_id CHAR(32) NOT NULL REFERENCES user(id),
|
||||||
starred_id BINARY(16) NOT NULL REFERENCES artist(id),
|
starred_id CHAR(32) NOT NULL REFERENCES artist(id),
|
||||||
date DATETIME NOT NULL,
|
date DATETIME NOT NULL,
|
||||||
PRIMARY KEY (user_id, starred_id)
|
PRIMARY KEY (user_id, starred_id)
|
||||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
@ -91,8 +91,8 @@ CREATE INDEX index_starred_artist_user_id_fk ON starred_artist(user_id);
|
|||||||
CREATE INDEX index_starred_artist_starred_id_fk ON starred_artist(starred_id);
|
CREATE INDEX index_starred_artist_starred_id_fk ON starred_artist(starred_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS starred_album (
|
CREATE TABLE IF NOT EXISTS starred_album (
|
||||||
user_id BINARY(16) NOT NULL REFERENCES user(id),
|
user_id CHAR(32) NOT NULL REFERENCES user(id),
|
||||||
starred_id BINARY(16) NOT NULL REFERENCES album(id),
|
starred_id CHAR(32) NOT NULL REFERENCES album(id),
|
||||||
date DATETIME NOT NULL,
|
date DATETIME NOT NULL,
|
||||||
PRIMARY KEY (user_id, starred_id)
|
PRIMARY KEY (user_id, starred_id)
|
||||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
@ -100,8 +100,8 @@ CREATE INDEX index_starred_album_user_id_fk ON starred_album(user_id);
|
|||||||
CREATE INDEX index_starred_album_starred_id_fk ON starred_album(starred_id);
|
CREATE INDEX index_starred_album_starred_id_fk ON starred_album(starred_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS starred_track (
|
CREATE TABLE IF NOT EXISTS starred_track (
|
||||||
user_id BINARY(16) NOT NULL REFERENCES user(id),
|
user_id CHAR(32) NOT NULL REFERENCES user(id),
|
||||||
starred_id BINARY(16) NOT NULL REFERENCES track(id),
|
starred_id CHAR(32) NOT NULL REFERENCES track(id),
|
||||||
date DATETIME NOT NULL,
|
date DATETIME NOT NULL,
|
||||||
PRIMARY KEY (user_id, starred_id)
|
PRIMARY KEY (user_id, starred_id)
|
||||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
@ -109,7 +109,7 @@ CREATE INDEX index_starred_track_user_id_fk ON starred_track(user_id);
|
|||||||
CREATE INDEX index_starred_track_starred_id_fk ON starred_track(starred_id);
|
CREATE INDEX index_starred_track_starred_id_fk ON starred_track(starred_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS rating_folder (
|
CREATE TABLE IF NOT EXISTS rating_folder (
|
||||||
user_id BINARY(16) NOT NULL REFERENCES user(id),
|
user_id CHAR(32) NOT NULL REFERENCES user(id),
|
||||||
rated_id INTEGER NOT NULL REFERENCES folder(id),
|
rated_id INTEGER NOT NULL REFERENCES folder(id),
|
||||||
rating INTEGER NOT NULL CHECK(rating BETWEEN 1 AND 5),
|
rating INTEGER NOT NULL CHECK(rating BETWEEN 1 AND 5),
|
||||||
PRIMARY KEY (user_id, rated_id)
|
PRIMARY KEY (user_id, rated_id)
|
||||||
@ -118,8 +118,8 @@ CREATE INDEX index_rating_folder_user_id_fk ON rating_folder(user_id);
|
|||||||
CREATE INDEX index_rating_folder_rated_id_fk ON rating_folder(rated_id);
|
CREATE INDEX index_rating_folder_rated_id_fk ON rating_folder(rated_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS rating_track (
|
CREATE TABLE IF NOT EXISTS rating_track (
|
||||||
user_id BINARY(16) NOT NULL REFERENCES user(id),
|
user_id CHAR(32) NOT NULL REFERENCES user(id),
|
||||||
rated_id BINARY(16) NOT NULL REFERENCES track(id),
|
rated_id CHAR(32) NOT NULL REFERENCES track(id),
|
||||||
rating INTEGER NOT NULL CHECK(rating BETWEEN 1 AND 5),
|
rating INTEGER NOT NULL CHECK(rating BETWEEN 1 AND 5),
|
||||||
PRIMARY KEY (user_id, rated_id)
|
PRIMARY KEY (user_id, rated_id)
|
||||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
@ -127,16 +127,16 @@ CREATE INDEX index_rating_track_user_id_fk ON rating_track(user_id);
|
|||||||
CREATE INDEX index_rating_track_rated_id_fk ON rating_track(rated_id);
|
CREATE INDEX index_rating_track_rated_id_fk ON rating_track(rated_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS chat_message (
|
CREATE TABLE IF NOT EXISTS chat_message (
|
||||||
id BINARY(16) PRIMARY KEY,
|
id CHAR(32) PRIMARY KEY,
|
||||||
user_id BINARY(16) NOT NULL REFERENCES user(id),
|
user_id CHAR(32) NOT NULL REFERENCES user(id),
|
||||||
time INTEGER NOT NULL,
|
time INTEGER NOT NULL,
|
||||||
message VARCHAR(512) NOT NULL
|
message VARCHAR(512) NOT NULL
|
||||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
CREATE INDEX index_chat_message_user_id_fk ON chat_message(user_id);
|
CREATE INDEX index_chat_message_user_id_fk ON chat_message(user_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS playlist (
|
CREATE TABLE IF NOT EXISTS playlist (
|
||||||
id BINARY(16) PRIMARY KEY,
|
id CHAR(32) PRIMARY KEY,
|
||||||
user_id BINARY(16) NOT NULL REFERENCES user(id),
|
user_id CHAR(32) NOT NULL REFERENCES user(id),
|
||||||
name VARCHAR(256) NOT NULL,
|
name VARCHAR(256) NOT NULL,
|
||||||
comment VARCHAR(256),
|
comment VARCHAR(256),
|
||||||
public BOOLEAN NOT NULL,
|
public BOOLEAN NOT NULL,
|
||||||
@ -151,7 +151,7 @@ CREATE TABLE meta (
|
|||||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS radio_station (
|
CREATE TABLE IF NOT EXISTS radio_station (
|
||||||
id BINARY(16) PRIMARY KEY,
|
id CHAR(32) PRIMARY KEY,
|
||||||
stream_url VARCHAR(256) NOT NULL,
|
stream_url VARCHAR(256) NOT NULL,
|
||||||
name VARCHAR(256) NOT NULL,
|
name VARCHAR(256) NOT NULL,
|
||||||
homepage_url VARCHAR(256),
|
homepage_url VARCHAR(256),
|
||||||
|
Loading…
Reference in New Issue
Block a user