قواعد البيانات والمخططات والمستخدمون
في هذا الدرس 11 موضوعات
هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.
Lesson Overview
You can now connect and look around. In this lesson you start organizing and securing what you build. PostgreSQL arranges things in layers, and the library picture fits them well: one server is the building; inside it, each database is a room; inside a room, each schema is a shelf unit that groups tables; and each user (the manual calls it a role) is a person with a key that opens some doors and not others.
You will create a user and a database for the Library application, connect as that user, and see why you should not do daily work as the all-powerful postgres account.
Why this matters: BEG-051's common-mistake list begins with "working as the postgres superuser". Setting up a dedicated user takes two commands, and it is the habit that keeps a coding slip from becoming a disaster.
This lesson builds on Lessons 1 and 2 (connecting with psql, \l, \dn, \du) and on BEG-050 (DDL and the idea of a table).
Learning Objectives
By the end of this lesson you will be able to:
- Describe the layers server, database, schema, and table, and where each lives.
- Create a user with
CREATE USERand a database withCREATE DATABASE ... OWNER. - Explain what a role, a superuser, and the
publicschema are. - Write a schema-qualified table name and explain the search path in one sentence.
- Connect as the application user and check who you are with
\conninfoorSELECT current_user;. - Explain why an application must not connect as
postgres.
Written Explanation
The layers
server (one installation)
database "library"
schema "public"
tables: authors, books, members, loans
schema "staging"
tables: ...
database "postgres"
...According to the PostgreSQL manual, a schema is a named container inside one database that holds tables and other objects. Two different schemas can contain tables with the same name, and schemas cannot be nested. Every new database starts with a schema named public, and an unqualified table name goes there. So CREATE TABLE books (...) is the same as CREATE TABLE public.books (...).
A database is a bigger boundary than a schema. When you connect with psql -d library, you connect to that one database; to work in another one you reconnect (in psql, \c name). That makes a database a natural unit for one application: Library data in library, something else in its own database.
Qualified names and the search path
You can name a table with its schema: staging.tmp_books. If you write just books, PostgreSQL looks through a list of schemas called the search path. The default setting is "$user", public. The first entry means "a schema named after the current user, if one exists", and since it normally does not, public is where plain names are found. SELECT current_schema(); tells you where new tables would be created.
For this course, you will keep to the public schema and use a second schema only to see how it works. Two schemas are useful when one database holds several areas, such as staging data separate from live data.
One recent change to know about: from PostgreSQL 15 on, ordinary users no longer get the right to create objects in public by default. The manual says databases upgraded from older versions keep the old behavior. In our setup the user who owns the database can create tables, which is why Lesson 6 works. If you ever get permission denied for schema public as a non-owner, that is the cause.
Roles, users, and superusers
PostgreSQL uses one concept, the role, for both individual people and groups. A role that can log in is what we usually call a user. CREATE USER is the same as CREATE ROLE plus the LOGIN attribute. Roles belong to the whole server, not to one database, so a name is unique across the installation.
Two attributes matter here. By default a new role is not a superuser (NOSUPERUSER) and cannot create databases (NOCREATEDB). A superuser bypasses all permission checks, which is why the manual advises granting it only when necessary. The postgres role created at installation is a superuser. You can see the difference with \du:
List of roles
Role name | Attributes
-------------+------------------------------------------------------------
library_app |
postgres | Superuser, Create role, Create DB, Replication, Bypass RLSlibrary_app has no special attributes: it can log in (it was created with CREATE USER) and own what it creates, and nothing more.
Creating the Library user and database
Connect as postgres once, for setup only:
CREATE USER library_app WITH PASSWORD 'change-me';
CREATE DATABASE library OWNER library_app;- The user is created first, because the database names it as its owner.
OWNER library_appmakes that user the owner of the new database. The manual says you can only name another role as owner if you may switch to that role, which a superuser can.'change-me'is a placeholder. A password typed into SQL like this travels to the server in plain text and may be saved in your client history or in the server log, as the manual forCREATE ROLEwarns. In real work, set the password with\password library_appinpsql, which sends it encrypted. For a local learning server a throwaway value is acceptable, but never reuse a real one.
CREATE DATABASE cannot be run inside a transaction block (Lesson 5 explains what that is), so run it by itself.
Now connect as the new user:
psql -U library_app -d libraryCheck who you are: SELECT current_user, current_database(); returns library_app and library.
Why not postgres?
The superuser can read, change, or drop everything: every database, every user. If your application connects as postgres, then:
- a bug (or a deliberate attack such as SQL injection, which later modules cover) can drop any database on the server;
- a leaked configuration file hands over total control, not just access to Library data;
- you cannot tell from the user name which application did something.
Giving each application its own user, which can reach only its own database, is called least privilege: give only the rights the job needs. You can see it working. Logged in as library_app, try to create a user or a database:
library=> CREATE ROLE intruder LOGIN;
ERROR: permission denied to create role
DETAIL: Only roles with the CREATEROLE attribute may create roles.
library=> CREATE DATABASE other;
ERROR: permission denied to create databaseThe prompt ends in => for an ordinary user and =# for a superuser. That small character is a handy reminder of how powerful your session is.
Note one limit on what this lesson claims: the database owner still has broad power inside its own database (it may create and drop tables there), which is exactly what the Lab needs. Finer-grained rights (granting only SELECT on some tables) come in later levels.
Examples
Example 1: listing rooms and keys (simple)
As postgres:
\l library
\du library_app Name | Owner | Encoding | ...
---------+-------------+----------+-----
library | library_app | UTF8 | ...The owner column shows that library_app owns the room. \du shows its empty attributes column. Both commands read information without changing anything.
Example 2: a second schema (practical)
Connected as library_app to library:
CREATE SCHEMA staging;
CREATE TABLE staging.tmp_books (id INTEGER PRIMARY KEY);
\dt staging.*
SHOW search_path;
SELECT current_schema(); Schema | Name | Type | Owner
---------+-----------+-------+-------------
staging | tmp_books | table | library_app
search_path
-----------------
"$user", public
current_schema
----------------
publicThe table lives on the staging shelf, not public. A plain SELECT * FROM tmp_books; would fail, because staging is not on the search path; staging.tmp_books works. If a table is "missing" and you can see it in a GUI, check its schema first.
Example 3: a user who tries too much (realistic)
A new teammate connects to library as library_app and runs a cleanup script that someone pasted from the internet. The script contains DROP DATABASE postgres; and CREATE ROLE backdoor SUPERUSER;. As library_app, the server refuses both, because the role has no such privileges (the earlier errors are what you see for creating a role or a database). The same script run as postgres would be dangerous. The restricted user did not stop all mistakes, but it limited the blast radius to one database.
Note that this example describes the permission checks you saw, rather than the exact errors for DROP DATABASE and SUPERUSER, which we did not run.
Backend Insight
Production systems usually have at least two kinds of database users. An administrator role is used by humans or migration tools to create and change structure. An application role is used by the running service and has only what it needs. Many teams go further and make the application role unable to drop tables at all. Whatever the exact design, the rule is that the credentials stored in your service's configuration should open as few doors as possible.
Names also matter. A user called library_app and a database called library make logs and error messages readable (library_app failed to insert into library). When you configure a Java connection later, you will supply exactly these values: host, port, database library, user library_app, and the password.
Common Mistakes
Mistake 1: Working as postgres because it "just works"
It works because it ignores every permission check, including the ones that would have caught your mistake. Use postgres to create users and databases, then switch.
Mistake 2: Putting a real password in a SQL script in Git
CREATE USER ... PASSWORD 'secret' in a committed file leaks the password. Use placeholders in files you commit and set real passwords with \password.
Mistake 3: Creating the database before the user
CREATE DATABASE library OWNER library_app; fails if the role does not exist yet. Order: role first, then database.
Mistake 4: Confusing schemas with databases
A schema is a folder inside one database; connecting to a different database requires a new connection, but moving between schemas does not. Tables in different databases cannot be referenced with a simple schema-qualified name.
Exercises
Try each exercise yourself before opening the solutions.
Level A: Foundation
A1. Put in order, largest to smallest: table, database, schema, server.
أظهر الحل A1
A1. Server, database, schema, table.
A2. What is the name of the default schema, and what does CREATE TABLE books (...) do with it?
أظهر الحل A2
A2. The default schema is public. An unqualified CREATE TABLE books creates public.books.
A3. What is the difference between CREATE ROLE x; and CREATE USER x;?
أظهر الحل A3
A3. CREATE USER is CREATE ROLE with LOGIN implied; a plain CREATE ROLE cannot log in unless you add LOGIN.
Level B: Application
B1. Write the two statements that create a user shop_app with a placeholder password and a database shop owned by it. Which one goes first and why?
أظهر الحل B1
B1. CREATE USER shop_app WITH PASSWORD 'change-me'; then CREATE DATABASE shop OWNER shop_app;. The user goes first because the database statement names it as owner and fails if it does not exist.
B2. After connecting, the prompt is shop=#. What does the # tell you, and should you be doing daily work in this session?
أظهر الحل B2
B2. # indicates a superuser session. No: use an ordinary user for daily work and keep the superuser for setup.
B3. A table staging.old_members exists, but SELECT * FROM old_members; fails with "does not exist". Why, and what are two ways to fix it?
أظهر الحل B3
B3. The table is in staging, which is not on the search path. Fix: write staging.old_members, or add the schema to the search path (SET search_path TO staging, public;) for the session.
Level C: Challenge
C1. A manager says "the app keeps getting permission errors, just connect it as postgres". Give a reasoned reply with two risks and one alternative.
أظهر الحل C1
C1. Risks: a bug or SQL injection could drop any database; a leaked configuration exposes the whole server. Alternative: find which privilege is missing (for example a table owned by someone else) and grant just that, or make the app user the owner of its own database as in this lesson.
C2. Design (in words) the database users for a small project with a developer who changes tables and a web application that only runs the service. State which attributes each needs and what you would avoid.
أظهر الحل C2
C2. Developer role: can log in and owns or may change the application's tables; no superuser. Application role: can log in and works only on the application's database, ideally with only the rights to read and change data, not to drop tables. Avoid superuser for both, shared passwords, and real passwords in committed files. Detailed granting is a later topic, so this is a design goal rather than a recipe.
Mini Challenge
On your own server, as postgres, create library_app and the library database owned by it. Then:
- Reconnect as
library_appand showSELECT current_user, current_database();. - Try
CREATE ROLE intruder LOGIN;and copy the error. - Create a schema
stagingwith one table in it and list it. - Write down in two sentences what the owner column of
\lshows and why that is better thanpostgres.
Check your work: you ran steps 1 to 3 as library_app, you set the password through the prompt or a throwaway placeholder, and no real password appears in your notes.
Summary & Next Lesson
Key takeaways
- A server contains databases; a database contains schemas; a schema contains tables.
publicis the default schema, and plain names are resolved through the search path.- A role that can log in is a user; the superuser (
postgres) bypasses all permission checks. - Create the user first, then
CREATE DATABASE ... OWNERthat user, and connect as it. - Least privilege limits damage from bugs and leaks; a prompt ending in
#means superuser.
Next lesson
The next lesson, "Constraints that protect data", moves into the library database and teaches the rules on the door: NOT NULL, UNIQUE, CHECK, and foreign keys, and what happens when someone tries to break them.
Self-check
- Which comes first:
CREATE USERorCREATE DATABASE ... OWNER? - What is the default schema called?
- What does
\dushow? - Name one reason not to connect the application as
postgres. - How can you tell from the prompt that you are a superuser?
أظهر الإجابات
CREATE USER, because the database statement names the owner.public.- The roles (users) on the server and their attributes, such as Superuser.
- A bug or a leaked password would give control of every database on the server.
- The prompt ends with
#(an ordinary user sees>).
References
- PostgreSQL documentation, Schemas. Supports: schema definition,
public, qualified names, the default"$user", publicsearch path, and the PostgreSQL 15 change toCREATEonpublic. - PostgreSQL documentation, Database Roles. Supports: roles are cluster-wide, a role may be a user or a group, superusers bypass checks.
- PostgreSQL documentation, CREATE ROLE. Supports:
CREATE USERimpliesLOGIN, defaults ofNOSUPERUSERandNOCREATEDB, and the warning about plaintext passwords in history and logs. - PostgreSQL documentation, CREATE DATABASE. Supports: the
OWNERoption and thatCREATE DATABASEcannot run in a transaction block. - The
permission deniederrors,\du, and\dnoutputs were produced on a local PostgreSQL 18.3 test server. The=>versus=#prompt convention is standardpsqlbehavior that I did not verify on the pages I read or in my test session (which ran from scripts without a visible prompt), so treat it as a common convention.
التطبيق
طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.
تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.