sql Module

One AND-group of conditions. A WHERE clause is a disjunction (OR) of these groups; a row matches the clause iff it matches every condition of some group (disjunctive normal form — no parentheses needed). The outcome of executing one statement. A SELECT fills colnames and the (nrows, ncols) cells grid; a DML statement fills count; DDL fills message. Both the REPL and the test suite consume this same structure, so output is asserted directly rather than scraped from text. source line -> token stream source line -> one statement AST statement AST -> result (drives the engine) source line -> result (lex + parse + exec) result -> printed to a unit (the REPL renderer)


Used by


Variables

Type Visibility Attributes Name Initial
integer, public, parameter :: TK_EOF = 0

End of input

integer, public, parameter :: TK_IDENT = 1

Word: keyword or identifier (case decided by the parser)

integer, public, parameter :: TK_INT = 2

Integer literal

integer, public, parameter :: TK_REAL = 3

Real literal

integer, public, parameter :: TK_STR = 4

Quoted string literal (already unescaped)

integer, public, parameter :: TK_PUNCT = 5

Operator / punctuation (=, <=, (, ,, *, …)

One lexical token. text is the verbatim source slice (for TK_STR it is the unescaped string body); col is the 1-based start column in the source line, used for parse-error reporting.

integer, public, parameter :: LIT_NULL = 0

SQL NULL

integer, public, parameter :: LIT_INT = 1

Integer literal

integer, public, parameter :: LIT_REAL = 2

Real literal

integer, public, parameter :: LIT_STR = 3

String literal

A parsed literal value, tagged by ltype.

integer, public, parameter :: OP_EQ = 1

=

integer, public, parameter :: OP_NE = 2

<>

integer, public, parameter :: OP_LT = 3

<

integer, public, parameter :: OP_LE = 4

<=

integer, public, parameter :: OP_GT = 5

>

integer, public, parameter :: OP_GE = 6

>=

integer, public, parameter :: OP_BETWEEN = 7

BETWEEN a AND b

integer, public, parameter :: OP_ISNULL = 8

IS NULL

integer, public, parameter :: OP_ISNOTNULL = 9

IS NOT NULL

One predicate condition: a column compared to one literal (lit), or a BETWEEN band (lit..lit2), or a null test (no literal).

integer, public, parameter :: ST_NONE = 0
integer, public, parameter :: ST_CREATE_TABLE = 1
integer, public, parameter :: ST_DROP_TABLE = 2
integer, public, parameter :: ST_CREATE_INDEX = 3
integer, public, parameter :: ST_DROP_INDEX = 4
integer, public, parameter :: ST_ADD_COLUMN = 5
integer, public, parameter :: ST_DROP_COLUMN = 6
integer, public, parameter :: ST_INSERT = 7
integer, public, parameter :: ST_DELETE = 8
integer, public, parameter :: ST_UPDATE = 9
integer, public, parameter :: ST_SELECT = 10
integer, public, parameter :: ST_BEGIN = 11
integer, public, parameter :: ST_COMMIT = 12
integer, public, parameter :: ST_ROLLBACK = 13

One parsed statement. A single fat record tagged by kind (a dispatch-table style union) rather than a polymorphic node hierarchy: each statement form populates the components it needs and leaves the rest at their defaults.

integer, public, parameter :: SQLRES_NONE = 0

Nothing to report (e.g. BEGIN)

integer, public, parameter :: SQLRES_ROWS = 1

A SELECT result set

integer, public, parameter :: SQLRES_COUNT = 2

A DML row count

integer, public, parameter :: SQLRES_MSG = 3

A short status message (DDL)

One rendered output cell of a SELECT result.


Interfaces

interface

Tokenise one source line. Always succeeds for well-formed tokens; reports SQR_INVALID with errmsg (carrying the offending column) for an unterminated string or a stray character. toks(1:ntok) are the tokens; a trailing TK_EOF is not appended (callers use ntok). Parse one statement. Recursive descent into sql_stmt_t. A trailing ; is permitted. Reports SQR_INVALID with a column-anchored errmsg on a syntax error. Execute one parsed statement against an open database, choosing an index-driven or scan-driven plan as appropriate, and fill res. Engine errors propagate through stat/errmsg. db is target because the transaction façade the executor calls needs it. Convenience: lex + parse + execute one source line. Equivalent to sql_parse then sql_exec. Render a result to a formatted unit: an aligned table for a SELECT, a "N row(s)" line for DML, or the message for DDL. Used by the REPL; tests inspect sql_result_t directly instead.

  • public module subroutine sql_lex(text, toks, ntok, stat, errmsg)

    Arguments

    Type IntentOptional Attributes Name
    character(len=*), intent(in) :: text

    Source line

    type(sql_token_t), intent(out), allocatable :: toks(:)

    Tokens

    integer, intent(out) :: ntok

    Token count

    integer, intent(out), optional :: stat

    SQR_OK / SQR_INVALID

    character(len=*), intent(inout), optional :: errmsg

    Failure detail

interface

Tokenise one source line. Always succeeds for well-formed tokens; reports SQR_INVALID with errmsg (carrying the offending column) for an unterminated string or a stray character. toks(1:ntok) are the tokens; a trailing TK_EOF is not appended (callers use ntok). Parse one statement. Recursive descent into sql_stmt_t. A trailing ; is permitted. Reports SQR_INVALID with a column-anchored errmsg on a syntax error. Execute one parsed statement against an open database, choosing an index-driven or scan-driven plan as appropriate, and fill res. Engine errors propagate through stat/errmsg. db is target because the transaction façade the executor calls needs it. Convenience: lex + parse + execute one source line. Equivalent to sql_parse then sql_exec. Render a result to a formatted unit: an aligned table for a SELECT, a "N row(s)" line for DML, or the message for DDL. Used by the REPL; tests inspect sql_result_t directly instead.

  • public module subroutine sql_parse(text, stmt, stat, errmsg)

    Arguments

    Type IntentOptional Attributes Name
    character(len=*), intent(in) :: text

    Source line

    type(sql_stmt_t), intent(out) :: stmt

    Parsed statement

    integer, intent(out), optional :: stat

    SQR_OK / SQR_INVALID

    character(len=*), intent(inout), optional :: errmsg

    Failure detail

interface

Tokenise one source line. Always succeeds for well-formed tokens; reports SQR_INVALID with errmsg (carrying the offending column) for an unterminated string or a stray character. toks(1:ntok) are the tokens; a trailing TK_EOF is not appended (callers use ntok). Parse one statement. Recursive descent into sql_stmt_t. A trailing ; is permitted. Reports SQR_INVALID with a column-anchored errmsg on a syntax error. Execute one parsed statement against an open database, choosing an index-driven or scan-driven plan as appropriate, and fill res. Engine errors propagate through stat/errmsg. db is target because the transaction façade the executor calls needs it. Convenience: lex + parse + execute one source line. Equivalent to sql_parse then sql_exec. Render a result to a formatted unit: an aligned table for a SELECT, a "N row(s)" line for DML, or the message for DDL. Used by the REPL; tests inspect sql_result_t directly instead.

  • public module subroutine sql_exec(db, stmt, res, stat, errmsg)

    Arguments

    Type IntentOptional Attributes Name
    type(db_t), intent(inout), target :: db

    Open database handle

    type(sql_stmt_t), intent(in) :: stmt

    Statement to run

    type(sql_result_t), intent(out) :: res

    Execution result

    integer, intent(out), optional :: stat

    SQR_OK or an error code

    character(len=*), intent(inout), optional :: errmsg

    Failure detail

interface

Tokenise one source line. Always succeeds for well-formed tokens; reports SQR_INVALID with errmsg (carrying the offending column) for an unterminated string or a stray character. toks(1:ntok) are the tokens; a trailing TK_EOF is not appended (callers use ntok). Parse one statement. Recursive descent into sql_stmt_t. A trailing ; is permitted. Reports SQR_INVALID with a column-anchored errmsg on a syntax error. Execute one parsed statement against an open database, choosing an index-driven or scan-driven plan as appropriate, and fill res. Engine errors propagate through stat/errmsg. db is target because the transaction façade the executor calls needs it. Convenience: lex + parse + execute one source line. Equivalent to sql_parse then sql_exec. Render a result to a formatted unit: an aligned table for a SELECT, a "N row(s)" line for DML, or the message for DDL. Used by the REPL; tests inspect sql_result_t directly instead.

  • public module subroutine sql_run(db, text, res, stat, errmsg)

    Arguments

    Type IntentOptional Attributes Name
    type(db_t), intent(inout), target :: db

    Open database handle

    character(len=*), intent(in) :: text

    Source line

    type(sql_result_t), intent(out) :: res

    Execution result

    integer, intent(out), optional :: stat

    SQR_OK or an error code

    character(len=*), intent(inout), optional :: errmsg

    Failure detail

interface

Tokenise one source line. Always succeeds for well-formed tokens; reports SQR_INVALID with errmsg (carrying the offending column) for an unterminated string or a stray character. toks(1:ntok) are the tokens; a trailing TK_EOF is not appended (callers use ntok). Parse one statement. Recursive descent into sql_stmt_t. A trailing ; is permitted. Reports SQR_INVALID with a column-anchored errmsg on a syntax error. Execute one parsed statement against an open database, choosing an index-driven or scan-driven plan as appropriate, and fill res. Engine errors propagate through stat/errmsg. db is target because the transaction façade the executor calls needs it. Convenience: lex + parse + execute one source line. Equivalent to sql_parse then sql_exec. Render a result to a formatted unit: an aligned table for a SELECT, a "N row(s)" line for DML, or the message for DDL. Used by the REPL; tests inspect sql_result_t directly instead.

  • public module subroutine sql_render(res, unit)

    Arguments

    Type IntentOptional Attributes Name
    type(sql_result_t), intent(in) :: res

    Result to print

    integer, intent(in) :: unit

    Output unit


Derived Types

type, public ::  sql_token_t

Components

Type Visibility Attributes Name Initial
integer, public :: kind = TK_EOF
character(len=:), public, allocatable :: text
integer, public :: col = 0

type, public ::  sql_lit_t

Components

Type Visibility Attributes Name Initial
integer, public :: ltype = LIT_NULL
integer(kind=int32), public :: ival = 0_int32
real(kind=real64), public :: rval = 0.0_real64
character(len=:), public, allocatable :: sval

type, public ::  sql_cond_t

Components

Type Visibility Attributes Name Initial
character(len=SQR_NAME_LEN), public :: col = ''
integer, public :: op = 0
type(sql_lit_t), public :: lit
type(sql_lit_t), public :: lit2

BETWEEN upper bound only

type, public ::  sql_cond_group_t

Components

Type Visibility Attributes Name Initial
type(sql_cond_t), public, allocatable :: conds(:)

type, public ::  sql_stmt_t

Components

Type Visibility Attributes Name Initial
integer, public :: kind = ST_NONE
character(len=SQR_NAME_LEN), public :: table = ''
type(column_t), public, allocatable :: coldefs(:)
character(len=SQR_NAME_LEN), public, allocatable :: names(:)
logical, public :: select_star = .false.

SELECT *

logical, public :: unique = .false.

CREATE UNIQUE INDEX

type(sql_lit_t), public, allocatable :: values(:,:)
logical, public :: insert_named = .false.

.true. if an explicit column list was given

character(len=SQR_NAME_LEN), public, allocatable :: set_cols(:)
type(sql_lit_t), public, allocatable :: set_vals(:)
logical, public :: has_where = .false.
type(sql_cond_group_t), public, allocatable :: where_groups(:)
logical, public :: has_order = .false.
character(len=SQR_NAME_LEN), public :: order_col = ''
logical, public :: order_desc = .false.
logical, public :: has_limit = .false.
integer, public :: limit_n = 0

type, public ::  sql_cell_t

Components

Type Visibility Attributes Name Initial
character(len=:), public, allocatable :: text
logical, public :: is_null = .false.

type, public ::  sql_result_t

Components

Type Visibility Attributes Name Initial
integer, public :: kind = SQLRES_NONE
character(len=SQR_NAME_LEN), public, allocatable :: colnames(:)
type(sql_cell_t), public, allocatable :: cells(:,:)
integer, public :: nrows = 0
integer, public :: ncols = 0
integer, public :: count = 0
character(len=:), public, allocatable :: message