mod_quotatab_sql
mod_quotatab
submodule is contained in the
mod_quotatab_sql.c
, and is found in the contrib/
area of the ProFTPD source distribution. See the mod_quotatab
installation instructions.
This submodule provides the SQL database "driver" for storing quota table information in SQL tables.
Please contact TJ Saunders <tj at castaglia.org> with any questions, concerns, or suggestions regarding this module.
2002-04-01: Thanks to Tomasz Konefal <tomk at compt.com> for his great feedback and support in developing this module.
2002-04-03: Thanks to Noah <sitz at onastick.net> for suggesting the better form of the UPDATE query.
2004-01-20: Thanks to Alex Ursu <alex.ursu at wapda.com> for supplying SQL Server FREEFORM query syntax.
mod_quotatab_sql
module supports the "sql" string
for the source-type parameter of the
QuotaLimitTable
and
QuotaTallyTable
configuration directives. If the "sql" source-type is used,
then the source-info parameter must be as described below. Note
that support for SQL-based quota tables requires the use of
mod_sql
.
mod_quotatab_sql
requires five SQL-related configuration
directives: SQLConnectInfo
, and four SQLNamedQuery
directives. The SQLConnectInfo
is needed to allow the module to
connect to the SQL database. The other four directives define the SQL queries
that will be used by mod_quotatab
for its storage/retrieval
operations involving quota data.
When using SQL tables and mod_sql
, the quota tables should appear
in the database named by the SQLConnectInfo
directive, which
will probably also contain the authentication information tables. This way
your proftpd
-specific tables are kept together. Also, it is
probably better to use a connection policy of PERSESSION, otherwise there will
be more overhead associated with each new connection made to the database for
each transaction; mod_quotatab
makes a lot of reads and writes to
its tables, each of which will require mod_quotatab_sql
to use a database connection.
One SQLNamedQuery
is needed to SELECT
quota
information from the limit table. The defined SQL statement for this
must return ten values, in the following order:
SQLNamedQuery
is needed to SELECT
quota
information from the tally table; the SQL statement defined for this
must return eight values, in the following order:
SQLNamedQuery
directives are used to define the
necessary UPDATE
and INSERT
operations on the
tally table. Failure to define any of the four required
SQLNamedQuery
directives will cause an error during
mod_quotatab_sql
's operation.
For SQL tables, the format for the QuotaLimitTable
directive
is:
QuotaLimitTable sql:/SELECT-SQLNamedQueryAnd, for the
QuotaTallyTable
directive:
QuotaTallyTable sql:/SELECT-SQLNamedQuery/UPDATE-SQLNamedQuery/INSERT-SQLNamedQuery
Also note that SQL-based tally tables have an issue with proper synchronization
of updates, especially when multiple sessions involving the same tally
are ocurring. In order to prevent the tally table from becoming out of
sync, you are strongly encouraged to define a QuotaLock
file.
SQL Quota Tables Example
Here are example SQLNamedQuery
directives to help demonstrate
how the mod_sql
hooks are used by mod_quotatab
.
These example SQL statements assume the existence of two tables: a
quotalimits
table that defines limit records, and a
quotatallies
table that holds the current tally records. Note
that these queries would appear all on a single line in your
proftpd.conf
.
SQLNamedQuery get-quota-limit SELECT "name, quota_type, per_session, limit_type, bytes_in_avail, \ bytes_out_avail, bytes_xfer_avail, files_in_avail, files_out_avail, files_xfer_avail FROM quotalimits \ WHERE name = '%{0}' AND quota_type = '%{1}'"This defines the SQL statement to return the required limit column values, in the necessary order. The
%{0}
and %{1}
meta
sequences will be substituted with the name being looked up (e.g. user
name, primary group name, class name (if in effect), or the empty string) and
the corresponding quota type (e.g. "user", "group",
"class", or "all"), respectively.
SQLNamedQuery get-quota-tally SELECT "name, quota_type, bytes_in_used, bytes_out_used, \ bytes_xfer_used, files_in_used, files_out_used, files_xfer_used FROM quotatallies \ WHERE name = '%{0}' AND quota_type = '%{1}'"Very similar to the above example, the SQL statement defined here is for the tally table, rather than the limit table. The meta sequences will be substituted with the same values as above.
SQLNamedQuery update-quota-tally UPDATE "bytes_in_used = bytes_in_used + %{0}, \ bytes_out_used = bytes_out_used + %{1}, bytes_xfer_used = bytes_xfer_used + %{2}, \ files_in_used = files_in_used + %{3}, files_out_used = files_out_used + %{4}, \ files_xfer_used = files_xfer_used + %{5} \ WHERE name = '%{6}' AND quota_type = '%{7}'" quotatalliesThis SQL statement is used to update the tally table with the current tally values for the session. The meta sequences will be substituted with the "deltas", the difference in the known versus current tallies. The reason for forming the UPDATE query this way is to provide as atomic an update operation as possible; this query will update the current values in the table at the time of the update, in order that any race condition between a SELECT and an UPDATE query on that information be reduced to as small a window as possible.
SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4}, %{5}, %{6}, %{7}" quotatalliesThis last SQL statement is used to create a new tally record, in the event that a limit record is found for the current session but no matching tally record is found. The meta sequences will be substituted with: name, quota type, upload tally in bytes, download tally in bytes, transfer tally in bytes, upload tally in files, download tally in files, and transfer tally in files, in that order. These values are initialized to zero for newly-created tally records by default.
Note: SQL Server uses a slightly different INSERT syntax. This means
that if you are using mod_quotatab_sql
in conjunction with the
mod_sql_tds
module to speak to a SQL Server, your INSERT
query may need to look like:
SQLNamedQuery insert-quota-tally FREEFORM \ "INSERT INTO quotatallies VALUES ('%{0}','%{1}','%{2}','%{3}','%{4}','%{5}','%{6}','%{7}')"
Now, using the above defined queries, the table configuration directives would be:
QuotaLock /var/run/ftpd/tally.lock QuotaLimitTable sql:/get-quota-limit QuotaTallyTable sql:/get-quota-tally/update-quota-tally/insert-quota-tally
Example Schema
Here are some example table schema for SQL-based quota tables:
CREATE TABLE quotalimits ( name VARCHAR(30), quota_type ENUM("user", "group", "class", "all") NOT NULL, per_session ENUM("false", "true") NOT NULL, limit_type ENUM("soft", "hard") NOT NULL, bytes_in_avail FLOAT NOT NULL, bytes_out_avail FLOAT NOT NULL, bytes_xfer_avail FLOAT NOT NULL, files_in_avail INT UNSIGNED NOT NULL, files_out_avail INT UNSIGNED NOT NULL, files_xfer_avail INT UNSIGNED NOT NULL );Postgres example:
CREATE TABLE quotalimits ( name VARCHAR(32) NOT NULL, quota_type VARCHAR(8) NOT NULL CHECK (quota_type IN ('user', 'group', 'class', 'all')), per_session BOOLEAN NOT NULL, limit_type VARCHAR(4) NOT NULL CHECK (limit_type IN ('soft', 'hard')), bytes_in_avail FLOAT NOT NULL, bytes_out_avail FLOAT NOT NULL, bytes_xfer_avail FLOAT NOT NULL, files_in_avail INT8 NOT NULL, files_out_avail INT8 NOT NULL, files_xfer_avail INT8 NOT NULL );
CREATE TABLE quotatallies ( name VARCHAR(30) NOT NULL, quota_type ENUM("user", "group", "class", "all") NOT NULL, bytes_in_used FLOAT NOT NULL, bytes_out_used FLOAT NOT NULL, bytes_xfer_used FLOAT NOT NULL, files_in_used INT UNSIGNED NOT NULL, files_out_used INT UNSIGNED NOT NULL, files_xfer_used INT UNSIGNED NOT NULL );Postgres example:
CREATE TABLE quotatallies ( name VARCHAR(32) NOT NULL, quota_type VARCHAR(8) NOT NULL CHECK (quota_type IN ('user','group','class','all')), bytes_in_used FLOAT NOT NULL, bytes_out_used FLOAT NOT NULL, bytes_xfer_used FLOAT NOT NULL, files_in_used INT8 NOT NULL, files_out_used INT8 NOT NULL, files_xfer_used INT8 NOT NULL );
mod_quotatab_sql
treats any number zero or less for a
bytes limit as "unlimited". Similarly, it treats a value of
zero for any of the files limits as "unlimited".
"Unlimited" values are ignored, in that any limit that is
"unlimited" is not used in any of mod_quotatab
's
calculations. NULL values should be avoided whenever possible.