├── .gitattributes ├── LICENSE ├── README.md ├── db_nimternalsql.nimble ├── htmldocs ├── db_nimternalsql.html ├── db_nimternalsql.idx ├── db_nimternalsql │ ├── duprem.html │ ├── duprem.idx │ ├── join.html │ ├── join.idx │ ├── like.html │ ├── like.idx │ ├── nqcommon.html │ ├── nqcommon.idx │ ├── nqtables.html │ ├── nqtables.idx │ ├── snapshot.html │ ├── snapshot.idx │ ├── sorter.html │ ├── sorter.idx │ ├── sqlparser.html │ ├── sqlparser.idx │ ├── sqlscanner.html │ ├── sqlscanner.idx │ ├── tx.html │ ├── tx.idx │ ├── union.html │ └── union.idx ├── dochack.js ├── nimdoc.out.css └── theindex.html ├── src ├── db_nimternalsql.nim └── db_nimternalsql │ ├── duprem.nim │ ├── groupby.nim │ ├── intersect.nim │ ├── join.nim │ ├── like.nim │ ├── nqcommon.nim │ ├── nqexcept.nim │ ├── nqtables.nim │ ├── snapshot.nim │ ├── sorter.nim │ ├── sqlparser.nim │ ├── sqlscanner.nim │ ├── tx.nim │ └── union.nim └── tests ├── alltests.nim ├── autoinc.nim ├── autoinc_txlog.nim ├── binary.nim ├── boolean.nim ├── cast.nim ├── char.nim ├── commit.nim ├── datetime.nim ├── default.nim ├── delete.nim ├── distinct.nim ├── except.nim ├── expjoin.nim ├── group.nim ├── impjoin.nim ├── insert_select.nim ├── intersect.nim ├── key.nim ├── leftjoin.nim ├── like.nim ├── nim.cfg ├── null.nim ├── numeric.nim ├── order.nim ├── prepared.nim ├── rollback.nim ├── snapshots.nim ├── subqueries.nim ├── txlog.nim ├── txlog_snapshot.nim ├── union.nim ├── update.nim ├── where.nim └── with.nim /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-vendored 2 | *.nim linguist-vendored=false 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Rene Hartmann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NimternalSQL, an in-memory SQL database for Nim 2 | 3 | NimternalSQL is a Nim library providing an in-memory SQL database. 4 | It uses the same interface as the Nim db_*.nim database wrappers. 5 | 6 | Tables are implemented using hash tables, so specifying a key using PRIMARY KEY is mandatory. 7 | Compound keys are supported. 8 | 9 | ## Data types 10 | 11 | The following data types are supported: 12 | 13 | * INTEGER 14 | * TEXT 15 | * CHAR 16 | * VARCHAR 17 | * DECIMAL 18 | * NUMERIC 19 | * REAL 20 | * DOUBLE PRECISION 21 | * BIGINT 22 | * BOOLEAN 23 | * BINARY 24 | * VARBINARY 25 | * LONGVARBINARY 26 | * RAW 27 | * BYTEA 28 | * TIME 29 | * DATE 30 | * TIMESTAMP 31 | 32 | DECIMAL and NUMERIC are internally represented as 64-bit integers. The maximum number of digits is 18. 33 | 34 | AUTOINCREMENT is supported on INTEGER and BIGINT columns. It is not restricted to key columns. 35 | 36 | ## Scalar operators 37 | 38 | Besides the usual arithmetic, comparison, and logical operators, NimternalSQL supports the following scalar operators: 39 | 40 | * || (string concatenation) 41 | * CASE 42 | * CAST 43 | * CHAR_LENGTH 44 | * CURRENT_DATE 45 | * CURRENT_TIME 46 | * CURRENT_TIMESTAMP 47 | * LENGTH 48 | * LOWER 49 | * UPPER 50 | * LIKE 51 | * OCTET_LENGTH 52 | * POSITION 53 | * SUBSTR 54 | * TRIM 55 | 56 | ## Persistence 57 | 58 | Persistence is supported through snapshots or (optionally) a transaction 59 | log. 60 | 61 | ## Transactions 62 | 63 | By default, NimternalSQL is in autocommit mode. Autocommit mode can be 64 | enabled or disabled using DbConn.setAutocommit(). 65 | 66 | ## Unimplemented SQL features 67 | 68 | A number of SQL features is not implemented, most notably: 69 | 70 | OUTER JOIN (JOIN .. ON, CROSS JOIN, and LEFT JOIN are supported) 71 | 72 | HAVING (GROUP BY is supported) 73 | 74 | RECURSIVE (WITH without RECURSIVE is supported) 75 | 76 | ALTER TABLE 77 | 78 | Views 79 | -------------------------------------------------------------------------------- /db_nimternalsql.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "1.3.2" 4 | author = "Rene Hartmann" 5 | description = "An in-memory SQL database library" 6 | license = "MIT" 7 | srcDir = "src" 8 | 9 | # Deps 10 | 11 | requires "nim >= 1.6.0" 12 | 13 | task test, "Runs all the tests": 14 | cd "tests" 15 | exec "nim c -r alltests.nim" 16 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql.idx: -------------------------------------------------------------------------------- 1 | DbConn db_nimternalsql.html#DbConn db_nimternalsql: DbConn 2 | Row db_nimternalsql.html#Row db_nimternalsql: Row 3 | open db_nimternalsql.html#open,string,string,string,string db_nimternalsql: open(connection, user, password, database: string): DbConn 4 | close db_nimternalsql.html#close,DbConn db_nimternalsql: close(db: DbConn) 5 | setAutocommit db_nimternalsql.html#setAutocommit,DbConn,bool db_nimternalsql: setAutocommit(db: DbConn; ac: bool) 6 | dbError db_nimternalsql.html#dbError,DbConn db_nimternalsql: dbError(db: DbConn) 7 | sqlState db_nimternalsql.html#sqlState,ref.DbError db_nimternalsql: sqlState(err: ref DbError): string 8 | exec db_nimternalsql.html#exec,DbConn,SqlQuery,varargs[string,] db_nimternalsql: exec(conn: DbConn; sql: SqlQuery; args: varargs[string, `$`]) 9 | exec db_nimternalsql.html#exec,DbConn,SqlPrepared,varargs[string,] db_nimternalsql: exec(conn: DbConn; stmt: SqlPrepared; args: varargs[string, `$`]) 10 | tryExec db_nimternalsql.html#tryExec,DbConn,SqlQuery,varargs[string,] db_nimternalsql: tryExec(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): bool 11 | tryExec db_nimternalsql.html#tryExec,DbConn,SqlPrepared,varargs[string,] db_nimternalsql: tryExec(db: DbConn; stmt: SqlPrepared; args: varargs[string, `$`]): bool 12 | execAffectedRows db_nimternalsql.html#execAffectedRows,DbConn,SqlQuery,varargs[string,] db_nimternalsql: execAffectedRows(conn: DbConn; sql: SqlQuery; args: varargs[string, `$`]): int64 13 | execAffectedRows db_nimternalsql.html#execAffectedRows,DbConn,SqlPrepared,varargs[string,] db_nimternalsql: execAffectedRows(conn: DbConn; stmt: SqlPrepared; args: varargs[string, `$`]): int64 14 | instantRows db_nimternalsql.html#instantRows.i,DbConn,SqlQuery,varargs[string,] db_nimternalsql: instantRows(conn: DbConn; sql: SqlQuery; args: varargs[string, `$`]): InstantRow 15 | instantRows db_nimternalsql.html#instantRows.i,DbConn,DbColumns,SqlQuery,varargs[string,] db_nimternalsql: instantRows(conn: DbConn; columns: var DbColumns; sql: SqlQuery;\n args: varargs[string, `$`]): InstantRow 16 | prepare db_nimternalsql.html#prepare,DbConn,SqlQuery db_nimternalsql: prepare(conn: DbConn; sql: SqlQuery): SqlPrepared 17 | instantRows db_nimternalsql.html#instantRows.i,DbConn,SqlPrepared,varargs[string,] db_nimternalsql: instantRows(conn: DbConn; sql: SqlPrepared; args: varargs[string, `$`]): InstantRow 18 | `[]` db_nimternalsql.html#[],InstantRow,int db_nimternalsql: `[]`(row: InstantRow; col: int): string 19 | len db_nimternalsql.html#len,InstantRow db_nimternalsql: len(row: InstantRow): int 20 | rows db_nimternalsql.html#rows.i,DbConn,SqlQuery,varargs[string,] db_nimternalsql: rows(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): Row 21 | rows db_nimternalsql.html#rows.i,DbConn,SqlPrepared,varargs[string,] db_nimternalsql: rows(db: DbConn; stmt: SqlPrepared; args: varargs[string, `$`]): Row 22 | getAllRows db_nimternalsql.html#getAllRows,DbConn,SqlQuery,varargs[string,] db_nimternalsql: getAllRows(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): seq[Row] 23 | getAllRows db_nimternalsql.html#getAllRows,DbConn,SqlPrepared,varargs[string,] db_nimternalsql: getAllRows(db: DbConn; stmt: SqlPrepared; args: varargs[string, `$`]): seq[Row] 24 | getRow db_nimternalsql.html#getRow,DbConn,SqlQuery,varargs[string,] db_nimternalsql: getRow(conn: DbConn; query: SqlQuery; args: varargs[string, `$`]): Row 25 | getRow db_nimternalsql.html#getRow,DbConn,SqlPrepared,varargs[string,] db_nimternalsql: getRow(conn: DbConn; stmt: SqlPrepared; args: varargs[string, `$`]): Row 26 | getValue db_nimternalsql.html#getValue,DbConn,SqlQuery,varargs[string,] db_nimternalsql: getValue(conn: DbConn; query: SqlQuery; args: varargs[string, `$`]): string 27 | getValue db_nimternalsql.html#getValue,DbConn,SqlPrepared,varargs[string,] db_nimternalsql: getValue(conn: DbConn; stmt: SqlPrepared; args: varargs[string, `$`]): string 28 | save db_nimternalsql.html#save,DbConn,string db_nimternalsql: save(conn: DbConn; filename: string) 29 | save db_nimternalsql.html#save,DbConn db_nimternalsql: save(conn: DbConn) 30 | restore db_nimternalsql.html#restore,DbConn,string db_nimternalsql: restore(conn: DbConn; filename: string) 31 | Examples db_nimternalsql.html#examples Examples 32 | Opening a connection to a database db_nimternalsql.html#examples-opening-a-connection-to-a-database Opening a connection to a database 33 | Creating a table db_nimternalsql.html#examples-creating-a-table Creating a table 34 | Inserting data db_nimternalsql.html#examples-inserting-data Inserting data 35 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/duprem.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | src/db_nimternalsql/duprem 21 | 22 | 23 | 24 | 25 | 67 | 68 | 69 | 70 |
71 |
72 |

src/db_nimternalsql/duprem

73 |
74 |
75 |
76 | 80 |     Dark Mode 81 |
82 | 89 |
90 | Search: 92 |
93 |
94 | Group by: 95 | 99 |
100 | 140 | 141 |
142 | 143 |
144 |
145 | 146 |

147 |
148 |

Imports

149 |
150 | nqtables 151 |
152 |
153 |

Types

154 |
155 |
156 |
DupRemTable = ref object of VTable
157 |   child*: VTable
158 | 
159 |
160 | 161 | 162 | 163 |
164 |
165 | 166 |
167 |
168 |

Procs

169 |
170 |
171 |
func newDupRemTable(child: VTable): VTable {....raises: [], tags: [].}
172 |
173 | 174 | 175 | 176 |
177 |
178 | 179 |
180 |
181 |

Methods

182 |
183 |
184 |
method getColumns(table: DupRemTable): DbColumns {....raises: [SqlError], tags: [].}
185 |
186 | 187 | 188 | 189 |
190 |
191 | 192 |
193 | 194 |
195 |
196 | 197 |
198 | 203 |
204 |
205 |
206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/duprem.idx: -------------------------------------------------------------------------------- 1 | DupRemTable db_nimternalsql/duprem.html#DupRemTable duprem: DupRemTable 2 | newDupRemTable db_nimternalsql/duprem.html#newDupRemTable,VTable duprem: newDupRemTable(child: VTable): VTable 3 | getColumns db_nimternalsql/duprem.html#getColumns.e,DupRemTable duprem: getColumns(table: DupRemTable): DbColumns 4 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/join.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | src/db_nimternalsql/join 21 | 22 | 23 | 24 | 25 | 67 | 68 | 69 | 70 |
71 |
72 |

src/db_nimternalsql/join

73 |
74 |
75 |
76 | 80 |     Dark Mode 81 |
82 | 89 |
90 | Search: 92 |
93 |
94 | Group by: 95 | 99 |
100 | 144 | 145 |
146 | 147 |
148 |
149 | 150 |

151 |
152 |

Imports

153 |
154 | nqcommon, nqtables 155 |
156 |
157 |

Types

158 |
159 |
160 |
JoinTable = ref object of VTable
161 |   children: array[2, VTable]
162 |   exp*: Expression
163 |   leftOuter*: bool
164 | 
165 |
166 | 167 | 168 | 169 |
170 |
171 | 172 |
173 |
174 |

Procs

175 |
176 |
177 |
func newJoinTable(lchild: VTable; rchild: VTable; leftOuter: bool = false;
178 |                   exp: Expression = nil): VTable {....raises: [], tags: [].}
179 |
180 | 181 | 182 | 183 |
184 |
185 | 186 |
187 |
188 |

Methods

189 |
190 |
191 |
method getColumns(table: JoinTable): DbColumns {....raises: [SqlError], tags: [].}
192 |
193 | 194 | 195 | 196 |
197 |
198 | 199 |
200 | 201 |
202 |
203 | 204 |
205 | 210 |
211 |
212 |
213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/join.idx: -------------------------------------------------------------------------------- 1 | JoinTable db_nimternalsql/join.html#JoinTable join: JoinTable 2 | newJoinTable db_nimternalsql/join.html#newJoinTable,VTable,VTable,bool,Expression join: newJoinTable(lchild: VTable; rchild: VTable; leftOuter: bool = false;\n exp: Expression = nil): VTable 3 | getColumns db_nimternalsql/join.html#getColumns.e,JoinTable join: getColumns(table: JoinTable): DbColumns 4 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/like.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | src/db_nimternalsql/like 21 | 22 | 23 | 24 | 25 | 67 | 68 | 69 | 70 |
71 |
72 |

src/db_nimternalsql/like

73 |
74 |
75 |
76 | 80 |     Dark Mode 81 |
82 | 89 |
90 | Search: 92 |
93 |
94 | Group by: 95 | 99 |
100 | 116 | 117 |
118 | 119 |
120 |
121 | 122 |

Unicode LIKE matching

123 |
124 |

Procs

125 |
126 |
127 |
func matchesLike(s: seq[Rune]; pattern: seq[Rune]; startAt: Natural = 0): bool {.
128 |     ...raises: [], tags: [].}
129 |
130 | 131 | 132 | 133 |
134 |
135 |
136 |
func matchesLike(s: string; pattern: string): bool {....raises: [], tags: [].}
137 |
138 | 139 | 140 | 141 |
142 |
143 | 144 |
145 | 146 |
147 |
148 | 149 |
150 | 155 |
156 |
157 |
158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/like.idx: -------------------------------------------------------------------------------- 1 | matchesLike db_nimternalsql/like.html#matchesLike,seq[Rune],seq[Rune],Natural like: matchesLike(s: seq[Rune]; pattern: seq[Rune]; startAt: Natural = 0): bool 2 | matchesLike db_nimternalsql/like.html#matchesLike,string,string like: matchesLike(s: string; pattern: string): bool 3 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/nqcommon.idx: -------------------------------------------------------------------------------- 1 | defaultDumpName db_nimternalsql/nqcommon.html#defaultDumpName nqcommon: defaultDumpName 2 | tooManyRowsReturnedBySubquery db_nimternalsql/nqcommon.html#tooManyRowsReturnedBySubquery nqcommon: tooManyRowsReturnedBySubquery 3 | stringTooLong db_nimternalsql/nqcommon.html#stringTooLong nqcommon: stringTooLong 4 | valueOutOfRange db_nimternalsql/nqcommon.html#valueOutOfRange nqcommon: valueOutOfRange 5 | invalidDatetimeValue db_nimternalsql/nqcommon.html#invalidDatetimeValue nqcommon: invalidDatetimeValue 6 | invalidParameterValue db_nimternalsql/nqcommon.html#invalidParameterValue nqcommon: invalidParameterValue 7 | columnNotNullable db_nimternalsql/nqcommon.html#columnNotNullable nqcommon: columnNotNullable 8 | uniqueConstraintViolation db_nimternalsql/nqcommon.html#uniqueConstraintViolation nqcommon: uniqueConstraintViolation 9 | syntaxError db_nimternalsql/nqcommon.html#syntaxError nqcommon: syntaxError 10 | columnRefAmbiguous db_nimternalsql/nqcommon.html#columnRefAmbiguous nqcommon: columnRefAmbiguous 11 | undefinedColumnName db_nimternalsql/nqcommon.html#undefinedColumnName nqcommon: undefinedColumnName 12 | undefinedObjectName db_nimternalsql/nqcommon.html#undefinedObjectName nqcommon: undefinedObjectName 13 | invalidGrouping db_nimternalsql/nqcommon.html#invalidGrouping nqcommon: invalidGrouping 14 | typeMismatch db_nimternalsql/nqcommon.html#typeMismatch nqcommon: typeMismatch 15 | undefinedFunction db_nimternalsql/nqcommon.html#undefinedFunction nqcommon: undefinedFunction 16 | tableExists db_nimternalsql/nqcommon.html#tableExists nqcommon: tableExists 17 | generalError db_nimternalsql/nqcommon.html#generalError nqcommon: generalError 18 | internalError db_nimternalsql/nqcommon.html#internalError nqcommon: internalError 19 | fileIoError db_nimternalsql/nqcommon.html#fileIoError nqcommon: fileIoError 20 | fileNotValid db_nimternalsql/nqcommon.html#fileNotValid nqcommon: fileNotValid 21 | notADirectory db_nimternalsql/nqcommon.html#notADirectory nqcommon: notADirectory 22 | restoreNotSupported db_nimternalsql/nqcommon.html#restoreNotSupported nqcommon: restoreNotSupported 23 | ColumnDef db_nimternalsql/nqcommon.html#ColumnDef nqcommon: ColumnDef 24 | TypeDef db_nimternalsql/nqcommon.html#TypeDef nqcommon: TypeDef 25 | Expression db_nimternalsql/nqcommon.html#Expression nqcommon: Expression 26 | ScalarLit db_nimternalsql/nqcommon.html#ScalarLit nqcommon: ScalarLit 27 | StringLit db_nimternalsql/nqcommon.html#StringLit nqcommon: StringLit 28 | NumericLit db_nimternalsql/nqcommon.html#NumericLit nqcommon: NumericLit 29 | BoolLit db_nimternalsql/nqcommon.html#BoolLit nqcommon: BoolLit 30 | TimeLit db_nimternalsql/nqcommon.html#TimeLit nqcommon: TimeLit 31 | TimestampLit db_nimternalsql/nqcommon.html#TimestampLit nqcommon: TimestampLit 32 | DateLit db_nimternalsql/nqcommon.html#DateLit nqcommon: DateLit 33 | NullLit db_nimternalsql/nqcommon.html#NullLit nqcommon: NullLit 34 | ScalarOpExp db_nimternalsql/nqcommon.html#ScalarOpExp nqcommon: ScalarOpExp 35 | QVarExp db_nimternalsql/nqcommon.html#QVarExp nqcommon: QVarExp 36 | ListExp db_nimternalsql/nqcommon.html#ListExp nqcommon: ListExp 37 | CaseExp db_nimternalsql/nqcommon.html#CaseExp nqcommon: CaseExp 38 | CastExp db_nimternalsql/nqcommon.html#CastExp nqcommon: CastExp 39 | SelectElement db_nimternalsql/nqcommon.html#SelectElement nqcommon: SelectElement 40 | SqlError db_nimternalsql/nqcommon.html#SqlError nqcommon: SqlError 41 | raiseDbError db_nimternalsql/nqcommon.html#raiseDbError,string,string nqcommon: raiseDbError(msg: string; sqlstate: string) 42 | newStringLit db_nimternalsql/nqcommon.html#newStringLit,string nqcommon: newStringLit(v: string): Expression 43 | newNumericLit db_nimternalsql/nqcommon.html#newNumericLit,string nqcommon: newNumericLit(v: string): Expression 44 | newTimeLit db_nimternalsql/nqcommon.html#newTimeLit,string nqcommon: newTimeLit(v: string): Expression 45 | newTimestampLit db_nimternalsql/nqcommon.html#newTimestampLit,string nqcommon: newTimestampLit(v: string): Expression 46 | newDateLit db_nimternalsql/nqcommon.html#newDateLit,string nqcommon: newDateLit(v: string): Expression 47 | newBoolLit db_nimternalsql/nqcommon.html#newBoolLit,bool nqcommon: newBoolLit(v: bool): Expression 48 | newNullLit db_nimternalsql/nqcommon.html#newNullLit nqcommon: newNullLit(): Expression 49 | newListExp db_nimternalsql/nqcommon.html#newListExp,seq[Expression] nqcommon: newListExp(v: seq[Expression]): Expression 50 | newScalarOpExp db_nimternalsql/nqcommon.html#newScalarOpExp,string,varargs[Expression] nqcommon: newScalarOpExp(name: string; args: varargs[Expression]): Expression 51 | newQVarExp db_nimternalsql/nqcommon.html#newQVarExp,string,string nqcommon: newQVarExp(name: string; tableName: string = ""): QVarExp 52 | newCaseExp db_nimternalsql/nqcommon.html#newCaseExp,Expression,seq[tuple[Expression,Expression]],Expression nqcommon: newCaseExp(exp: Expression;\n whens: seq[tuple[cond: Expression, exp: Expression]];\n elseExp: Expression): Expression 53 | newCastExp db_nimternalsql/nqcommon.html#newCastExp,Expression,TypeDef nqcommon: newCastExp(exp: Expression; typ: TypeDef): Expression 54 | `$` db_nimternalsql/nqcommon.html#$.e,Expression nqcommon: `$`(exp: Expression): string 55 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/nqtables.idx: -------------------------------------------------------------------------------- 1 | maxPrecision db_nimternalsql/nqtables.html#maxPrecision nqtables: maxPrecision 2 | XColumnDef db_nimternalsql/nqtables.html#XColumnDef nqtables: XColumnDef 3 | BaseTable db_nimternalsql/nqtables.html#BaseTable nqtables: BaseTable 4 | Database db_nimternalsql/nqtables.html#Database nqtables: Database 5 | Record db_nimternalsql/nqtables.html#Record nqtables: Record 6 | kInt db_nimternalsql/nqtables.html#kInt MatValueKind.kInt 7 | kNumeric db_nimternalsql/nqtables.html#kNumeric MatValueKind.kNumeric 8 | kFloat db_nimternalsql/nqtables.html#kFloat MatValueKind.kFloat 9 | kString db_nimternalsql/nqtables.html#kString MatValueKind.kString 10 | kBool db_nimternalsql/nqtables.html#kBool MatValueKind.kBool 11 | kNull db_nimternalsql/nqtables.html#kNull MatValueKind.kNull 12 | kBigint db_nimternalsql/nqtables.html#kBigint MatValueKind.kBigint 13 | kTime db_nimternalsql/nqtables.html#kTime MatValueKind.kTime 14 | kDate db_nimternalsql/nqtables.html#kDate MatValueKind.kDate 15 | MatValueKind db_nimternalsql/nqtables.html#MatValueKind nqtables: MatValueKind 16 | MatValue db_nimternalsql/nqtables.html#MatValue nqtables: MatValue 17 | HashBaseTable db_nimternalsql/nqtables.html#HashBaseTable nqtables: HashBaseTable 18 | nqkNull db_nimternalsql/nqtables.html#nqkNull NqValueKind.nqkNull 19 | nqkInt db_nimternalsql/nqtables.html#nqkInt NqValueKind.nqkInt 20 | nqkNumeric db_nimternalsql/nqtables.html#nqkNumeric NqValueKind.nqkNumeric 21 | nqkFloat db_nimternalsql/nqtables.html#nqkFloat NqValueKind.nqkFloat 22 | nqkString db_nimternalsql/nqtables.html#nqkString NqValueKind.nqkString 23 | nqkBool db_nimternalsql/nqtables.html#nqkBool NqValueKind.nqkBool 24 | nqkList db_nimternalsql/nqtables.html#nqkList NqValueKind.nqkList 25 | nqkBigint db_nimternalsql/nqtables.html#nqkBigint NqValueKind.nqkBigint 26 | nqkTime db_nimternalsql/nqtables.html#nqkTime NqValueKind.nqkTime 27 | nqkDate db_nimternalsql/nqtables.html#nqkDate NqValueKind.nqkDate 28 | nqkTimestamp db_nimternalsql/nqtables.html#nqkTimestamp NqValueKind.nqkTimestamp 29 | NqValueKind db_nimternalsql/nqtables.html#NqValueKind nqtables: NqValueKind 30 | NqValue db_nimternalsql/nqtables.html#NqValue nqtables: NqValue 31 | VarResolver db_nimternalsql/nqtables.html#VarResolver nqtables: VarResolver 32 | VTable db_nimternalsql/nqtables.html#VTable nqtables: VTable 33 | BaseTableRef db_nimternalsql/nqtables.html#BaseTableRef nqtables: BaseTableRef 34 | WhereTable db_nimternalsql/nqtables.html#WhereTable nqtables: WhereTable 35 | ProjectTable db_nimternalsql/nqtables.html#ProjectTable nqtables: ProjectTable 36 | ColumnAssignment db_nimternalsql/nqtables.html#ColumnAssignment nqtables: ColumnAssignment 37 | InstantRow db_nimternalsql/nqtables.html#InstantRow nqtables: InstantRow 38 | Cursor db_nimternalsql/nqtables.html#Cursor nqtables: Cursor 39 | newInstantRow db_nimternalsql/nqtables.html#newInstantRow,VTable,seq[NqValue] nqtables: newInstantRow(table: VTable; vals: seq[NqValue]): InstantRow 40 | newMatInstantRow db_nimternalsql/nqtables.html#newMatInstantRow,VTable,Record[MatValue] nqtables: newMatInstantRow(table: VTable; key: Record[MatValue]): InstantRow 41 | newWhereTable db_nimternalsql/nqtables.html#newWhereTable,VTable,Expression nqtables: newWhereTable(child: VTable; whereExp: Expression): VTable 42 | newProjectTable db_nimternalsql/nqtables.html#newProjectTable,VTable,seq[SelectElement] nqtables: newProjectTable(child: VTable; columns: seq[SelectElement]): VTable 43 | columnNo db_nimternalsql/nqtables.html#columnNo.e,VTable,string,string nqtables: columnNo(rtable: VTable; name: string; tableName: string): int 44 | isQVarExp db_nimternalsql/nqtables.html#isQVarExp,Expression nqtables: isQVarExp(exp: Expression): bool 45 | hash db_nimternalsql/nqtables.html#hash,NqValue nqtables: hash(v: NqValue): Hash 46 | toNum db_nimternalsql/nqtables.html#toNum,NqValue nqtables: toNum(v: NqValue): NqValue 47 | toNumeric db_nimternalsql/nqtables.html#toNumeric,NqValue nqtables: toNumeric(v: NqValue): NqValue 48 | toFloat db_nimternalsql/nqtables.html#toFloat,NqValue nqtables: toFloat(v: NqValue): float 49 | adjustScale db_nimternalsql/nqtables.html#adjustScale,NqValue,NqValue nqtables: adjustScale(a: var NqValue; b: var NqValue) 50 | toNqValue db_nimternalsql/nqtables.html#toNqValue,MatValue,ColumnDef nqtables: toNqValue(v: MatValue; colDef: ColumnDef): NqValue 51 | checkType db_nimternalsql/nqtables.html#checkType,ColumnDef nqtables: checkType(def: ColumnDef) 52 | setScale db_nimternalsql/nqtables.html#setScale,NqValue,Natural nqtables: setScale(v: NqValue; scale: Natural): NqValue 53 | toMatValue db_nimternalsql/nqtables.html#toMatValue,NqValue,ColumnDef nqtables: toMatValue(v: NqValue; colDef: ColumnDef): MatValue 54 | `==` db_nimternalsql/nqtables.html#==,seq,seq nqtables: `==`(r1: seq; r2: seq): bool 55 | newHashBaseTable db_nimternalsql/nqtables.html#newHashBaseTable,string,openArray[ColumnDef],seq[string] nqtables: newHashBaseTable(name: string; columns: openArray[ColumnDef]; key: seq[string]): HashBaseTable 56 | newDatabase db_nimternalsql/nqtables.html#newDatabase nqtables: newDatabase(): Database 57 | keyIndex db_nimternalsql/nqtables.html#keyIndex,BaseTable,int nqtables: keyIndex(table: BaseTable; col: int): int 58 | isKey db_nimternalsql/nqtables.html#isKey,BaseTable,int nqtables: isKey(table: BaseTable; col: int): bool 59 | getTable db_nimternalsql/nqtables.html#getTable,Database,string nqtables: getTable(db: Database; tableName: string): BaseTable 60 | eval db_nimternalsql/nqtables.html#eval.e,Expression,VarResolver,AggrResolver nqtables: eval(exp: Expression; varResolver: VarResolver; aggrResolver: AggrResolver = proc (\n exp: ScalarOpExp): NqValue = raiseDbError(exp.opName & " not supported",\n undefinedFunction)): NqValue 61 | eval db_nimternalsql/nqtables.html#eval.e,StringLit,VarResolver,AggrResolver nqtables: eval(exp: StringLit; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 62 | eval db_nimternalsql/nqtables.html#eval.e,NumericLit,VarResolver,AggrResolver nqtables: eval(exp: NumericLit; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 63 | eval db_nimternalsql/nqtables.html#eval.e,TimeLit,VarResolver,AggrResolver nqtables: eval(exp: TimeLit; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 64 | eval db_nimternalsql/nqtables.html#eval.e,TimestampLit,VarResolver,AggrResolver nqtables: eval(exp: TimestampLit; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 65 | eval db_nimternalsql/nqtables.html#eval.e,DateLit,VarResolver,AggrResolver nqtables: eval(exp: DateLit; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 66 | eval db_nimternalsql/nqtables.html#eval.e,BoolLit,VarResolver,AggrResolver nqtables: eval(exp: BoolLit; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 67 | eval db_nimternalsql/nqtables.html#eval.e,NullLit,VarResolver,AggrResolver nqtables: eval(exp: NullLit; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 68 | `+` db_nimternalsql/nqtables.html#+,NqValue,NqValue nqtables: `+`(a: NqValue; b: NqValue): NqValue 69 | newCursor db_nimternalsql/nqtables.html#newCursor.e,VTable,openArray[string] nqtables: newCursor(table: VTable; args: openArray[string]): Cursor 70 | next db_nimternalsql/nqtables.html#next.e,Cursor,InstantRow,VarResolver nqtables: next(cursor: Cursor; row: var InstantRow; varResolver: VarResolver = nil): bool 71 | instantRows db_nimternalsql/nqtables.html#instantRows.i,VTable,varargs[string],VarResolver nqtables: instantRows(rtable: VTable; args: varargs[string]; varResolver: VarResolver): InstantRow 72 | columnCount db_nimternalsql/nqtables.html#columnCount.e,VTable nqtables: columnCount(table: VTable): Natural 73 | columnCount db_nimternalsql/nqtables.html#columnCount,InstantRow nqtables: columnCount(row: InstantRow): int 74 | eval db_nimternalsql/nqtables.html#eval.e,ScalarOpExp,VarResolver,AggrResolver nqtables: eval(exp: ScalarOpExp; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 75 | getAggrs db_nimternalsql/nqtables.html#getAggrs,seq[SelectElement] nqtables: getAggrs(sels: seq[SelectElement]): seq[Expression] 76 | eval db_nimternalsql/nqtables.html#eval.e,QVarExp,VarResolver,AggrResolver nqtables: eval(exp: QVarExp; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 77 | eval db_nimternalsql/nqtables.html#eval.e,ListExp,VarResolver,AggrResolver nqtables: eval(exp: ListExp; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 78 | eval db_nimternalsql/nqtables.html#eval.e,VTable,VarResolver,AggrResolver nqtables: eval(exp: VTable; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 79 | eval db_nimternalsql/nqtables.html#eval.e,CaseExp,VarResolver,AggrResolver nqtables: eval(exp: CaseExp; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 80 | `$` db_nimternalsql/nqtables.html#$,NqValue nqtables: `$`(val: NqValue): string 81 | eval db_nimternalsql/nqtables.html#eval.e,CastExp,VarResolver,AggrResolver nqtables: eval(exp: CastExp; varResolver: VarResolver; aggrResolver: AggrResolver): NqValue 82 | columnNo db_nimternalsql/nqtables.html#columnNo.e,BaseTable,string nqtables: columnNo(rtable: BaseTable; name: string): int 83 | columnValueAt db_nimternalsql/nqtables.html#columnValueAt,InstantRow,Natural nqtables: columnValueAt(row: InstantRow; col: Natural): NqValue 84 | getColumns db_nimternalsql/nqtables.html#getColumns.e,VTable nqtables: getColumns(table: VTable): DbColumns 85 | getColumns db_nimternalsql/nqtables.html#getColumns.e,BaseTableRef nqtables: getColumns(table: BaseTableRef): DbColumns 86 | getColumns db_nimternalsql/nqtables.html#getColumns.e,WhereTable nqtables: getColumns(table: WhereTable): DbColumns 87 | columnNo db_nimternalsql/nqtables.html#columnNo,VTable,QVarExp nqtables: columnNo(table: VTable; colRef: QVarExp): int 88 | getColumns db_nimternalsql/nqtables.html#getColumns.e,ProjectTable nqtables: getColumns(table: ProjectTable): DbColumns 89 | setColumnValueAt db_nimternalsql/nqtables.html#setColumnValueAt,HashBaseTable,Record[MatValue],Natural,MatValue nqtables: setColumnValueAt(table: HashBaseTable; keyRecord: var Record[MatValue];\n col: Natural; val: MatValue) 90 | setColumnValueAt db_nimternalsql/nqtables.html#setColumnValueAt,InstantRow,Natural,NqValue nqtables: setColumnValueAt(row: var InstantRow; col: Natural; val: NqValue) 91 | instantRows db_nimternalsql/nqtables.html#instantRows.i,BaseTableRef nqtables: instantRows(tableRef: BaseTableRef): InstantRow 92 | isConst db_nimternalsql/nqtables.html#isConst,Expression nqtables: isConst(exp: Expression): bool 93 | expKeyCols db_nimternalsql/nqtables.html#expKeyCols,Expression,BaseTableRef,proc(Expression),openArray[string] nqtables: expKeyCols(exp: Expression; tableRef: BaseTableRef;\n isConstProc: proc (exp: Expression): bool; args: openArray[string]): seq[\n tuple[colNo: Natural, exp: Expression]] 94 | isKeyUpdate db_nimternalsql/nqtables.html#isKeyUpdate,BaseTable,seq[ColumnAssignment] nqtables: isKeyUpdate(table: BaseTable; assignments: seq[ColumnAssignment]): bool 95 | contains db_nimternalsql/nqtables.html#contains.e,VTable,InstantRow nqtables: contains(table: VTable; row: InstantRow): bool 96 | contains db_nimternalsql/nqtables.html#contains.e,BaseTableRef,InstantRow nqtables: contains(table: BaseTableRef; row: InstantRow): bool 97 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/snapshot.idx: -------------------------------------------------------------------------------- 1 | writeError db_nimternalsql/snapshot.html#writeError snapshot: writeError 2 | readErrorMissingData db_nimternalsql/snapshot.html#readErrorMissingData snapshot: readErrorMissingData 3 | writeValue db_nimternalsql/snapshot.html#writeValue,File,MatValue snapshot: writeValue(f: File; val: MatValue) 4 | writeRecord db_nimternalsql/snapshot.html#writeRecord,File,Record snapshot: writeRecord(f: File; rec: Record) 5 | writeName db_nimternalsql/snapshot.html#writeName,File,string snapshot: writeName(f: File; name: string) 6 | writeTableDef db_nimternalsql/snapshot.html#writeTableDef,File,BaseTable snapshot: writeTableDef(f: File; table: BaseTable) 7 | save db_nimternalsql/snapshot.html#save,Database,string snapshot: save(db: Database; filename: string) 8 | readValue db_nimternalsql/snapshot.html#readValue,File snapshot: readValue(f: File): MatValue 9 | readRecord db_nimternalsql/snapshot.html#readRecord,File snapshot: readRecord(f: File): Record[MatValue] 10 | readName db_nimternalsql/snapshot.html#readName,File snapshot: readName(f: File): string 11 | readTableDef db_nimternalsql/snapshot.html#readTableDef,File,BaseTable snapshot: readTableDef(f: File; table: BaseTable) 12 | restore db_nimternalsql/snapshot.html#restore,Database,string snapshot: restore(db: Database; filename: string) 13 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/sorter.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | src/db_nimternalsql/sorter 21 | 22 | 23 | 24 | 25 | 67 | 68 | 69 | 70 |
71 |
72 |

src/db_nimternalsql/sorter

73 |
74 |
75 |
76 | 80 |     Dark Mode 81 |
82 | 89 |
90 | Search: 92 |
93 |
94 | Group by: 95 | 99 |
100 | 138 | 139 |
140 | 141 |
142 |
143 | 144 |

145 |
146 |

Imports

147 |
148 | nqcommon, nqtables 149 |
150 |
151 |

Procs

152 |
153 |
154 |
proc cmp(v1: NqValue; v2: NqValue): int {....raises: [SqlError], tags: [].}
155 |
156 | 157 | 158 | 159 |
160 |
161 |
162 |
func newSortedTable(child: VTable; order: seq[tuple[col: Natural, asc: bool]];
163 |                     removeDuplicates: bool = false): VTable {....raises: [],
164 |     tags: [].}
165 |
166 | 167 | 168 | 169 |
170 |
171 | 172 |
173 |
174 |

Methods

175 |
176 |
177 |
method getColumns(table: SortedTable): DbColumns {....raises: [SqlError], tags: [].}
178 |
179 | 180 | 181 | 182 |
183 |
184 | 185 |
186 | 187 |
188 |
189 | 190 |
191 | 196 |
197 |
198 |
199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/sorter.idx: -------------------------------------------------------------------------------- 1 | newSortedTable db_nimternalsql/sorter.html#newSortedTable,VTable,seq[tuple[Natural,bool]],bool sorter: newSortedTable(child: VTable; order: seq[tuple[col: Natural, asc: bool]];\n removeDuplicates: bool = false): VTable 2 | cmp db_nimternalsql/sorter.html#cmp,NqValue,NqValue sorter: cmp(v1: NqValue; v2: NqValue): int 3 | getColumns db_nimternalsql/sorter.html#getColumns.e,SortedTable sorter: getColumns(table: SortedTable): DbColumns 4 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/sqlparser.idx: -------------------------------------------------------------------------------- 1 | trkSimpleTableRef db_nimternalsql/sqlparser.html#trkSimpleTableRef SqlTableRefKind.trkSimpleTableRef 2 | trkRelOp db_nimternalsql/sqlparser.html#trkRelOp SqlTableRefKind.trkRelOp 3 | SqlTableRefKind db_nimternalsql/sqlparser.html#SqlTableRefKind sqlparser: SqlTableRefKind 4 | SqlTableRef db_nimternalsql/sqlparser.html#SqlTableRef sqlparser: SqlTableRef 5 | SqlStatement db_nimternalsql/sqlparser.html#SqlStatement sqlparser: SqlStatement 6 | SqlSelect db_nimternalsql/sqlparser.html#SqlSelect sqlparser: SqlSelect 7 | SqlCreateTable db_nimternalsql/sqlparser.html#SqlCreateTable sqlparser: SqlCreateTable 8 | SqlDropTable db_nimternalsql/sqlparser.html#SqlDropTable sqlparser: SqlDropTable 9 | ikValues db_nimternalsql/sqlparser.html#ikValues SqlInsertKind.ikValues 10 | ikSelect db_nimternalsql/sqlparser.html#ikSelect SqlInsertKind.ikSelect 11 | SqlInsertKind db_nimternalsql/sqlparser.html#SqlInsertKind sqlparser: SqlInsertKind 12 | SqlInsert db_nimternalsql/sqlparser.html#SqlInsert sqlparser: SqlInsert 13 | UpdateAssignment db_nimternalsql/sqlparser.html#UpdateAssignment sqlparser: UpdateAssignment 14 | SqlUpdate db_nimternalsql/sqlparser.html#SqlUpdate sqlparser: SqlUpdate 15 | SqlDelete db_nimternalsql/sqlparser.html#SqlDelete sqlparser: SqlDelete 16 | SqlCommit db_nimternalsql/sqlparser.html#SqlCommit sqlparser: SqlCommit 17 | SqlRollback db_nimternalsql/sqlparser.html#SqlRollback sqlparser: SqlRollback 18 | OrderByElement db_nimternalsql/sqlparser.html#OrderByElement sqlparser: OrderByElement 19 | tekSelect db_nimternalsql/sqlparser.html#tekSelect TableExpKind.tekSelect 20 | tekUnion db_nimternalsql/sqlparser.html#tekUnion TableExpKind.tekUnion 21 | tekExcept db_nimternalsql/sqlparser.html#tekExcept TableExpKind.tekExcept 22 | tekIntersect db_nimternalsql/sqlparser.html#tekIntersect TableExpKind.tekIntersect 23 | TableExpKind db_nimternalsql/sqlparser.html#TableExpKind sqlparser: TableExpKind 24 | TableExp db_nimternalsql/sqlparser.html#TableExp sqlparser: TableExp 25 | NamedTableExp db_nimternalsql/sqlparser.html#NamedTableExp sqlparser: NamedTableExp 26 | QueryExp db_nimternalsql/sqlparser.html#QueryExp sqlparser: QueryExp 27 | parseStatement db_nimternalsql/sqlparser.html#parseStatement,Reader sqlparser: parseStatement(reader: Reader): SqlStatement 28 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/sqlscanner.idx: -------------------------------------------------------------------------------- 1 | tokAll db_nimternalsql/sqlscanner.html#tokAll TokenKind.tokAll 2 | tokAnd db_nimternalsql/sqlscanner.html#tokAnd TokenKind.tokAnd 3 | tokAny db_nimternalsql/sqlscanner.html#tokAny TokenKind.tokAny 4 | tokAs db_nimternalsql/sqlscanner.html#tokAs TokenKind.tokAs 5 | tokAsc db_nimternalsql/sqlscanner.html#tokAsc TokenKind.tokAsc 6 | tokAutoincrement db_nimternalsql/sqlscanner.html#tokAutoincrement TokenKind.tokAutoincrement 7 | tokBy db_nimternalsql/sqlscanner.html#tokBy TokenKind.tokBy 8 | tokChar db_nimternalsql/sqlscanner.html#tokChar TokenKind.tokChar 9 | tokDefault db_nimternalsql/sqlscanner.html#tokDefault TokenKind.tokDefault 10 | tokDrop db_nimternalsql/sqlscanner.html#tokDrop TokenKind.tokDrop 11 | tokVarchar db_nimternalsql/sqlscanner.html#tokVarchar TokenKind.tokVarchar 12 | tokNumeric db_nimternalsql/sqlscanner.html#tokNumeric TokenKind.tokNumeric 13 | tokCase db_nimternalsql/sqlscanner.html#tokCase TokenKind.tokCase 14 | tokCast db_nimternalsql/sqlscanner.html#tokCast TokenKind.tokCast 15 | tokWhen db_nimternalsql/sqlscanner.html#tokWhen TokenKind.tokWhen 16 | tokThen db_nimternalsql/sqlscanner.html#tokThen TokenKind.tokThen 17 | tokElse db_nimternalsql/sqlscanner.html#tokElse TokenKind.tokElse 18 | tokEnd db_nimternalsql/sqlscanner.html#tokEnd TokenKind.tokEnd 19 | tokCommit db_nimternalsql/sqlscanner.html#tokCommit TokenKind.tokCommit 20 | tokRollback db_nimternalsql/sqlscanner.html#tokRollback TokenKind.tokRollback 21 | tokCreate db_nimternalsql/sqlscanner.html#tokCreate TokenKind.tokCreate 22 | tokCross db_nimternalsql/sqlscanner.html#tokCross TokenKind.tokCross 23 | tokCount db_nimternalsql/sqlscanner.html#tokCount TokenKind.tokCount 24 | tokDecimal db_nimternalsql/sqlscanner.html#tokDecimal TokenKind.tokDecimal 25 | tokDelete db_nimternalsql/sqlscanner.html#tokDelete TokenKind.tokDelete 26 | tokDesc db_nimternalsql/sqlscanner.html#tokDesc TokenKind.tokDesc 27 | tokDistinct db_nimternalsql/sqlscanner.html#tokDistinct TokenKind.tokDistinct 28 | tokDouble db_nimternalsql/sqlscanner.html#tokDouble TokenKind.tokDouble 29 | tokTime db_nimternalsql/sqlscanner.html#tokTime TokenKind.tokTime 30 | tokTimestamp db_nimternalsql/sqlscanner.html#tokTimestamp TokenKind.tokTimestamp 31 | tokTrim db_nimternalsql/sqlscanner.html#tokTrim TokenKind.tokTrim 32 | tokLeading db_nimternalsql/sqlscanner.html#tokLeading TokenKind.tokLeading 33 | tokTrailing db_nimternalsql/sqlscanner.html#tokTrailing TokenKind.tokTrailing 34 | tokBoth db_nimternalsql/sqlscanner.html#tokBoth TokenKind.tokBoth 35 | tokPrecision db_nimternalsql/sqlscanner.html#tokPrecision TokenKind.tokPrecision 36 | tokExists db_nimternalsql/sqlscanner.html#tokExists TokenKind.tokExists 37 | tokFrom db_nimternalsql/sqlscanner.html#tokFrom TokenKind.tokFrom 38 | tokGroup db_nimternalsql/sqlscanner.html#tokGroup TokenKind.tokGroup 39 | tokIf db_nimternalsql/sqlscanner.html#tokIf TokenKind.tokIf 40 | tokInsert db_nimternalsql/sqlscanner.html#tokInsert TokenKind.tokInsert 41 | tokUpdate db_nimternalsql/sqlscanner.html#tokUpdate TokenKind.tokUpdate 42 | tokSet db_nimternalsql/sqlscanner.html#tokSet TokenKind.tokSet 43 | tokIn db_nimternalsql/sqlscanner.html#tokIn TokenKind.tokIn 44 | tokIs db_nimternalsql/sqlscanner.html#tokIs TokenKind.tokIs 45 | tokInto db_nimternalsql/sqlscanner.html#tokInto TokenKind.tokInto 46 | tokJoin db_nimternalsql/sqlscanner.html#tokJoin TokenKind.tokJoin 47 | tokKey db_nimternalsql/sqlscanner.html#tokKey TokenKind.tokKey 48 | tokLike db_nimternalsql/sqlscanner.html#tokLike TokenKind.tokLike 49 | tokNot db_nimternalsql/sqlscanner.html#tokNot TokenKind.tokNot 50 | tokOn db_nimternalsql/sqlscanner.html#tokOn TokenKind.tokOn 51 | tokOr db_nimternalsql/sqlscanner.html#tokOr TokenKind.tokOr 52 | tokOrder db_nimternalsql/sqlscanner.html#tokOrder TokenKind.tokOrder 53 | tokPrimary db_nimternalsql/sqlscanner.html#tokPrimary TokenKind.tokPrimary 54 | tokSelect db_nimternalsql/sqlscanner.html#tokSelect TokenKind.tokSelect 55 | tokTable db_nimternalsql/sqlscanner.html#tokTable TokenKind.tokTable 56 | tokUnion db_nimternalsql/sqlscanner.html#tokUnion TokenKind.tokUnion 57 | tokIntersect db_nimternalsql/sqlscanner.html#tokIntersect TokenKind.tokIntersect 58 | tokExcept db_nimternalsql/sqlscanner.html#tokExcept TokenKind.tokExcept 59 | tokValues db_nimternalsql/sqlscanner.html#tokValues TokenKind.tokValues 60 | tokWhere db_nimternalsql/sqlscanner.html#tokWhere TokenKind.tokWhere 61 | tokWith db_nimternalsql/sqlscanner.html#tokWith TokenKind.tokWith 62 | tokLeft db_nimternalsql/sqlscanner.html#tokLeft TokenKind.tokLeft 63 | tokInner db_nimternalsql/sqlscanner.html#tokInner TokenKind.tokInner 64 | tokOuter db_nimternalsql/sqlscanner.html#tokOuter TokenKind.tokOuter 65 | tokPosition db_nimternalsql/sqlscanner.html#tokPosition TokenKind.tokPosition 66 | tokAsterisk db_nimternalsql/sqlscanner.html#tokAsterisk TokenKind.tokAsterisk 67 | tokDiv db_nimternalsql/sqlscanner.html#tokDiv TokenKind.tokDiv 68 | tokPlus db_nimternalsql/sqlscanner.html#tokPlus TokenKind.tokPlus 69 | tokNull db_nimternalsql/sqlscanner.html#tokNull TokenKind.tokNull 70 | tokMinus db_nimternalsql/sqlscanner.html#tokMinus TokenKind.tokMinus 71 | tokRightParen db_nimternalsql/sqlscanner.html#tokRightParen TokenKind.tokRightParen 72 | tokLeftParen db_nimternalsql/sqlscanner.html#tokLeftParen TokenKind.tokLeftParen 73 | tokComma db_nimternalsql/sqlscanner.html#tokComma TokenKind.tokComma 74 | tokDot db_nimternalsql/sqlscanner.html#tokDot TokenKind.tokDot 75 | tokEq db_nimternalsql/sqlscanner.html#tokEq TokenKind.tokEq 76 | tokNeq db_nimternalsql/sqlscanner.html#tokNeq TokenKind.tokNeq 77 | tokLt db_nimternalsql/sqlscanner.html#tokLt TokenKind.tokLt 78 | tokLe db_nimternalsql/sqlscanner.html#tokLe TokenKind.tokLe 79 | tokGt db_nimternalsql/sqlscanner.html#tokGt TokenKind.tokGt 80 | tokGe db_nimternalsql/sqlscanner.html#tokGe TokenKind.tokGe 81 | tokConcat db_nimternalsql/sqlscanner.html#tokConcat TokenKind.tokConcat 82 | tokIdentifier db_nimternalsql/sqlscanner.html#tokIdentifier TokenKind.tokIdentifier 83 | tokString db_nimternalsql/sqlscanner.html#tokString TokenKind.tokString 84 | tokInt db_nimternalsql/sqlscanner.html#tokInt TokenKind.tokInt 85 | tokRat db_nimternalsql/sqlscanner.html#tokRat TokenKind.tokRat 86 | tokTrue db_nimternalsql/sqlscanner.html#tokTrue TokenKind.tokTrue 87 | tokFalse db_nimternalsql/sqlscanner.html#tokFalse TokenKind.tokFalse 88 | tokPlaceholder db_nimternalsql/sqlscanner.html#tokPlaceholder TokenKind.tokPlaceholder 89 | tokNumPlaceholder db_nimternalsql/sqlscanner.html#tokNumPlaceholder TokenKind.tokNumPlaceholder 90 | tokEndOfInput db_nimternalsql/sqlscanner.html#tokEndOfInput TokenKind.tokEndOfInput 91 | TokenKind db_nimternalsql/sqlscanner.html#TokenKind sqlscanner: TokenKind 92 | Token db_nimternalsql/sqlscanner.html#Token sqlscanner: Token 93 | Reader db_nimternalsql/sqlscanner.html#Reader sqlscanner: Reader 94 | FileReader db_nimternalsql/sqlscanner.html#FileReader sqlscanner: FileReader 95 | StringReader db_nimternalsql/sqlscanner.html#StringReader sqlscanner: StringReader 96 | Scanner db_nimternalsql/sqlscanner.html#Scanner sqlscanner: Scanner 97 | newStringReader db_nimternalsql/sqlscanner.html#newStringReader,string sqlscanner: newStringReader(s: string): StringReader 98 | newFileReader db_nimternalsql/sqlscanner.html#newFileReader,File sqlscanner: newFileReader(f: File): FileReader 99 | newScanner db_nimternalsql/sqlscanner.html#newScanner,Reader sqlscanner: newScanner(r: Reader): Scanner 100 | currentToken db_nimternalsql/sqlscanner.html#currentToken,Scanner sqlscanner: currentToken(s: Scanner): Token 101 | nextToken db_nimternalsql/sqlscanner.html#nextToken,Scanner sqlscanner: nextToken(s: Scanner): Token 102 | isValidTime db_nimternalsql/sqlscanner.html#isValidTime,string sqlscanner: isValidTime(str: string): bool 103 | isValidTimestamp db_nimternalsql/sqlscanner.html#isValidTimestamp,string sqlscanner: isValidTimestamp(str: string): bool 104 | isValidDate db_nimternalsql/sqlscanner.html#isValidDate,string sqlscanner: isValidDate(str: string): bool 105 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/tx.idx: -------------------------------------------------------------------------------- 1 | Tx db_nimternalsql/tx.html#Tx tx: Tx 2 | newTx db_nimternalsql/tx.html#newTx,string,File tx: newTx(logPath: string; file: File): Tx 3 | createBaseTable db_nimternalsql/tx.html#createBaseTable,Tx,Database,string,openArray[ColumnDef],seq[string] tx: createBaseTable(tx: Tx; db: Database; name: string;\n columns: openArray[ColumnDef]; key: seq[string]): BaseTable 4 | dropBaseTable db_nimternalsql/tx.html#dropBaseTable,Tx,Database,string tx: dropBaseTable(tx: Tx; db: Database; name: string) 5 | insert db_nimternalsql/tx.html#insert,Tx,BaseTable,seq[NqValue] tx: insert(tx: Tx; table: BaseTable; values: seq[NqValue]) 6 | delete db_nimternalsql/tx.html#delete,Tx,BaseTable,Expression,openArray[string] tx: delete(tx: Tx; table: BaseTable; whereExp: Expression; args: openArray[string]): int64 7 | update db_nimternalsql/tx.html#update,Tx,BaseTable,seq[ColumnAssignment],Expression,openArray[string] tx: update(tx: Tx; table: BaseTable; assignments: seq[ColumnAssignment];\n whereExp: Expression; args: openArray[string]): int64 8 | commit db_nimternalsql/tx.html#commit,Tx tx: commit(tx: Tx) 9 | rollback db_nimternalsql/tx.html#rollback,Tx,Database tx: rollback(tx: Tx; db: Database) 10 | openLog db_nimternalsql/tx.html#openLog,string,Database tx: openLog(logdir: string; db: Database): File 11 | closeLog db_nimternalsql/tx.html#closeLog,Tx tx: closeLog(tx: Tx) 12 | logIsActive db_nimternalsql/tx.html#logIsActive,Tx tx: logIsActive(tx: Tx): bool 13 | truncateLog db_nimternalsql/tx.html#truncateLog,Tx tx: truncateLog(tx: Tx) 14 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/union.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | src/db_nimternalsql/union 21 | 22 | 23 | 24 | 25 | 67 | 68 | 69 | 70 |
71 |
72 |

src/db_nimternalsql/union

73 |
74 |
75 |
76 | 80 |     Dark Mode 81 |
82 | 89 |
90 | Search: 92 |
93 |
94 | Group by: 95 | 99 |
100 | 136 | 137 |
138 | 139 |
140 |
141 | 142 |

143 |
144 |

Imports

145 |
146 | nqcommon, nqtables 147 |
148 |
149 |

Procs

150 |
151 |
152 |
func newUnionTable(lchild: VTable; rchild: VTable): VTable {....raises: [SqlError],
153 |     tags: [].}
154 |
155 | 156 | 157 | 158 |
159 |
160 | 161 |
162 |
163 |

Methods

164 |
165 |
166 |
method columnNo(table: UnionTable; name: string; tableName: string): int {.
167 |     ...raises: [SqlError], tags: [].}
168 |
169 | 170 | 171 | 172 |
173 |
174 |
175 |
method getColumns(table: UnionTable): DbColumns {....raises: [SqlError], tags: [].}
176 |
177 | 178 | 179 | 180 |
181 |
182 | 183 |
184 | 185 |
186 |
187 | 188 |
189 | 194 |
195 |
196 |
197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /htmldocs/db_nimternalsql/union.idx: -------------------------------------------------------------------------------- 1 | newUnionTable db_nimternalsql/union.html#newUnionTable,VTable,VTable union: newUnionTable(lchild: VTable; rchild: VTable): VTable 2 | columnNo db_nimternalsql/union.html#columnNo.e,UnionTable,string,string union: columnNo(table: UnionTable; name: string; tableName: string): int 3 | getColumns db_nimternalsql/union.html#getColumns.e,UnionTable union: getColumns(table: UnionTable): DbColumns 4 | -------------------------------------------------------------------------------- /src/db_nimternalsql/duprem.nim: -------------------------------------------------------------------------------- 1 | import nqtables 2 | import db_common 3 | import sets 4 | 5 | type 6 | DupRemTable* = ref object of VTable 7 | child*: VTable 8 | DupRemTableCursor = ref object of Cursor 9 | table: DupRemTable 10 | iter: iterator(cursor: DupRemTableCursor): InstantRow 11 | rows: HashSet[seq[NqValue]] 12 | 13 | func newDupRemTable*(child: VTable): VTable = 14 | result = DupRemTable(child: child) 15 | 16 | method columnCount(table: DupRemTable): Natural = 17 | result = columnCount(table.child) 18 | 19 | method columnNo(table: DupRemTable, name: string, tableName: string): int = 20 | return table.child.columnNo(name, tableName) 21 | 22 | iterator instantRows(cursor: DupRemTableCursor): InstantRow {.closure.} = 23 | for r in cursor.rows.items: 24 | yield newInstantRow(cursor.table.child, r) 25 | 26 | method newCursor(table: DupRemTable, args: openArray[string]): Cursor = 27 | let childCursor = newCursor(table.child, args) 28 | let columnCount = columnCount(table) 29 | var row: InstantRow 30 | var rows: seq[seq[NqValue]] 31 | while childCursor.next(row): 32 | var destRow: seq[NqValue] 33 | for i in 0.. 0 20 | rightMatch: bool # true if a row from the right was returned 21 | # which matched the current row of the left table 22 | 23 | func newJoinTable*(lchild: VTable, rchild: VTable, 24 | leftOuter: bool = false, 25 | exp: Expression = nil): VTable = 26 | result = JoinTable(children: [lchild, rchild], 27 | leftOuter: leftOuter, exp: exp) 28 | 29 | method columnCount(table: JoinTable): Natural = 30 | result = columnCount(table.children[0]) + columnCount(table.children[1]) 31 | 32 | method columnNo(table: JoinTable, name: string, tableName: string): int = 33 | let col1 = table.children[0].columnNo(name, tableName) 34 | let col2 = table.children[1].columnNo(name, tableName); 35 | 36 | if col1 == -1 and col2 == -1: 37 | return -1; 38 | if col1 != -1 and col2 != -1: 39 | raiseDbError("column reference \"" & (if tableName != "": tableName & "." else: "") & 40 | name & "\" is ambiguous", columnRefAmbiguous) 41 | result = if col1 != -1: col1 else: columnCount(table.children[0]) + col2 42 | 43 | func join(row1: InstantRow, row2: InstantRow, table: VTable): InstantRow = 44 | var vals = seq[NqValue](@[]) 45 | for i in 0.. 0: 140 | return nextByKey(cursor, row, varResolver) 141 | var rrow: InstantRow 142 | while true: 143 | if cursor.advanceLeft: 144 | cursor.advanceLeft = false 145 | if not cursor.childCursors[0].next(cursor.row, varResolver): 146 | return false 147 | cursor.rightMatch = false 148 | if cursor.childCursors[1].next(rrow): 149 | row = join(cursor.row, rrow, cursor.table) 150 | if evalJoinCond(cursor, row): 151 | cursor.rightMatch = true 152 | return true 153 | else: 154 | continue 155 | if cursor.table.leftOuter and not cursor.rightMatch: 156 | row = join(cursor.row, 157 | newInstantRow(cursor.table.children[1], 158 | repeat(NqValue(kind: nqkNull), 159 | cursor.table.children[1].columnCount)), 160 | cursor.table) 161 | cursor.advanceLeft = true 162 | return true 163 | if not cursor.childCursors[0].next(cursor.row, varResolver): 164 | return false 165 | cursor.childCursors[1] = newCursor(cursor.table.children[1], cursor.args) 166 | cursor.rightMatch = false 167 | if cursor.childCursors[1].next(rrow, varResolver): 168 | row = join(cursor.row, rrow, cursor.table) 169 | if evalJoinCond(cursor, row): 170 | cursor.rightMatch = true 171 | return true 172 | result = false 173 | 174 | method getColumns*(table: JoinTable): DbColumns = 175 | for i in 0..1: 176 | var cols = table.children[i].getColumns() 177 | for j in 0..= pattern.len: 13 | return false 14 | case pattern[patIdx]: 15 | of matchSingle: 16 | idx += 1 17 | patIdx += 1 18 | of matchMany: 19 | for i in idx..s.len: 20 | if matchesLike(s, pattern[patIdx + 1..pattern.high], i): 21 | return true 22 | return false 23 | else: 24 | if s[idx] != pattern[patIdx]: 25 | return false 26 | idx += 1 27 | patIdx += 1 28 | for c in pattern[patIdx..pattern.high]: 29 | if c != matchMany: 30 | return false 31 | result = true 32 | 33 | func matchesLike*(s: string, pattern: string): bool = 34 | result = matchesLike(toRunes(s), toRunes(pattern)) 35 | -------------------------------------------------------------------------------- /src/db_nimternalsql/nqcommon.nim: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2020, 2022 Rene Hartmann 3 | # 4 | # See the file LICENSE for details about the copyright. 5 | # 6 | import db_common 7 | 8 | const 9 | defaultDumpName* = "dump.ndb" 10 | 11 | tooManyRowsReturnedBySubquery* = "21000" 12 | stringTooLong* = "22001" 13 | valueOutOfRange* = "22003" 14 | invalidDatetimeValue* = "22007" 15 | invalidParameterValue* = "22023" 16 | columnNotNullable* = "23502" 17 | uniqueConstraintViolation* = "23505" 18 | syntaxError* = "42601" 19 | columnRefAmbiguous* = "42702" 20 | undefinedColumnName* = "42703" 21 | undefinedObjectName* = "42704" 22 | invalidGrouping* = "42803" 23 | typeMismatch* = "42804" 24 | undefinedFunction* = "42883" 25 | tableExists* = "42N01" 26 | generalError* = "HY000" 27 | internalError* = "N0000" 28 | fileIoError* = "N0001" 29 | fileNotValid* = "N0002" 30 | notADirectory* = "N0003" 31 | restoreNotSupported* = "NS004" 32 | 33 | type 34 | ColumnDef* = object of RootObj 35 | name*: string 36 | typ*: string 37 | size*: Natural 38 | precision*: Natural 39 | scale*: Natural 40 | notNull*: bool 41 | defaultValue*: Expression 42 | primaryKey*: bool # unused in BaseTable 43 | autoincrement*: bool 44 | TypeDef* = object 45 | typ*: string 46 | size*: Natural 47 | precision*: Natural 48 | scale*: Natural 49 | 50 | Expression* = ref object of RootObj 51 | ScalarLit* = ref object of Expression 52 | val*: string 53 | StringLit* {.final.} = ref object of ScalarLit 54 | NumericLit* {.final.} = ref object of ScalarLit 55 | BoolLit* {.final.} = ref object of ScalarLit 56 | TimeLit* {.final.} = ref object of ScalarLit 57 | TimestampLit* {.final.} = ref object of ScalarLit 58 | DateLit* {.final.} = ref object of ScalarLit 59 | NullLit* {.final.} = ref object of Expression 60 | ScalarOpExp* {.acyclic.} = ref object of Expression 61 | opName*: string 62 | args*: seq[Expression] 63 | QVarExp* = ref object of Expression 64 | name*: string 65 | tableName*: string 66 | ListExp* {.acyclic.} = ref object of Expression 67 | exps*: seq[Expression] 68 | CaseExp* {.acyclic.} = ref object of Expression 69 | exp*: Expression 70 | whens*: seq[tuple[cond: Expression, exp: Expression]] 71 | elseExp*: Expression 72 | CastExp* {.acyclic.} = ref object of Expression 73 | exp*: Expression 74 | typeDef*: TypeDef 75 | SelectElement* {.acyclic.} = object 76 | colName*: string 77 | exp*: Expression 78 | 79 | SqlError* = object of DbError 80 | sqlState*: string 81 | 82 | proc raiseDbError*(msg: string, sqlstate: string) {.noreturn.} = 83 | var 84 | e: ref SqlError 85 | new(e) 86 | e.msg = msg 87 | e.sqlState = sqlstate 88 | raise e 89 | 90 | func newStringLit*(v: string): Expression = 91 | result = StringLit(val: v) 92 | 93 | func newNumericLit*(v: string): Expression = 94 | result = NumericLit(val: v) 95 | 96 | func newTimeLit*(v: string): Expression = 97 | result = TimeLit(val: v) 98 | 99 | func newTimestampLit*(v: string): Expression = 100 | result = TimestampLit(val: v) 101 | 102 | func newDateLit*(v: string): Expression = 103 | result = DateLit(val: v) 104 | 105 | func newBoolLit*(v: bool): Expression = 106 | result = BoolLit(val: if v: "TRUE" else: "FALSE") 107 | 108 | func newNullLit*(): Expression = 109 | result = NullLit() 110 | 111 | func newListExp*(v: seq[Expression]): Expression = 112 | result = ListExp(exps: v) 113 | 114 | func newScalarOpExp*(name: string, args: varargs[Expression]): Expression = 115 | result = ScalarOpExp(opName: name, args: @args) 116 | 117 | func newQVarExp*(name: string, tableName: string = ""): QVarExp = 118 | result = QVarExp(name: name, tableName: tableName) 119 | 120 | func newCaseExp*(exp: Expression, 121 | whens: seq[tuple[cond: Expression, exp: Expression]], 122 | elseExp: Expression): Expression = 123 | result = CaseExp(exp: exp, whens: whens, elseExp: elseExp) 124 | 125 | func newCastExp*(exp: Expression, typ: TypeDef): Expression = 126 | result = CastExp(exp: exp, typedef: typ) 127 | 128 | method `$`*(exp: Expression): string {.base.} = nil 129 | 130 | method `$`(exp: ScalarLit): string = 131 | result = exp.val 132 | 133 | method `$`(exp: ScalarOpExp): string = 134 | result = exp.opName & '(' 135 | for i in 0..= cursor.rows.len: 69 | return false 70 | row = newInstantRow(cursor.table, cursor.rows[cursor.nextRow]) 71 | cursor.nextRow += 1 72 | if not cursor.table.removeDuplicates or 73 | cursor.nextRow < 2 or cursor.rows[cursor.nextRow - 1] != cursor.rows[cursor.nextRow - 2]: 74 | return true 75 | 76 | method getColumns*(table: SortedTable): DbColumns = 77 | result = table.child.getColumns() 78 | -------------------------------------------------------------------------------- /src/db_nimternalsql/sqlscanner.nim: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2020, 2022 Rene Hartmann 3 | # 4 | # See the file LICENSE for details about the copyright. 5 | # 6 | import strutils 7 | import nqcommon 8 | import times 9 | 10 | type 11 | TokenKind* = enum 12 | tokAll, tokAnd, tokAny, tokAs, tokAsc, tokAutoincrement, 13 | tokBy, tokChar, tokDefault, 14 | tokDrop, tokVarchar, tokNumeric, tokCase, tokCast, tokWhen, 15 | tokThen, tokElse, tokEnd, tokCommit, tokRollback, tokCreate, 16 | tokCross, tokCount, tokDecimal, 17 | tokDelete, tokDesc, tokDistinct, tokDouble, tokTime, tokTimestamp, 18 | tokTrim, tokLeading, tokTrailing, tokBoth, 19 | tokPrecision, tokExists, 20 | tokFrom, tokGroup, tokIf, tokInsert, tokUpdate, tokSet, tokIn, tokIs, 21 | tokInto, tokJoin, tokKey, tokLike, tokNot, tokOn, tokOr, tokOrder, 22 | tokPrimary, tokSelect, tokTable, tokUnion, tokIntersect, tokExcept, 23 | tokValues, tokWhere, tokWith, 24 | tokLeft, tokInner, tokOuter, tokPosition, 25 | tokAsterisk, tokDiv, tokPlus, tokNull, tokMinus, tokRightParen, 26 | tokLeftParen, tokComma, tokDot, tokEq, tokNeq, tokLt, tokLe, tokGt, tokGe, 27 | tokConcat, tokIdentifier, tokString, tokInt, tokRat, tokTrue, tokFalse, 28 | tokPlaceholder, tokNumPlaceholder, tokEndOfInput 29 | Token* = object 30 | case kind*: TokenKind 31 | of tokIdentifier: 32 | identifier*: string 33 | of tokString, tokInt, tokRat: 34 | value*: string 35 | else: discard 36 | 37 | Reader* = ref object of RootObj 38 | FileReader* = ref object of Reader 39 | file: File 40 | nextChar: char 41 | eof: bool 42 | StringReader* = ref object of Reader 43 | buf: string 44 | current: int 45 | 46 | Scanner* = ref object 47 | reader: Reader 48 | current: Token 49 | 50 | method read(reader: Reader): char {.base.} = nil 51 | method peek(reader: Reader): char {.base.} = nil 52 | 53 | proc newStringReader*(s: string): StringReader = 54 | result = StringReader(buf: s, current: 0) 55 | 56 | method read(reader: StringReader): char = 57 | if reader.current >= reader.buf.len(): 58 | raise newException(EOFError, "end of input string") 59 | result = reader.buf[reader.current] 60 | reader.current += 1 61 | 62 | method peek(reader: StringReader): char = 63 | if reader.current < reader.buf.len(): 64 | result = reader.buf[reader.current] 65 | else: 66 | result = '\0' 67 | 68 | proc newFileReader*(f: File): FileReader = 69 | result = FileReader(file: f, eof: false) 70 | try: 71 | result.nextChar = f.readChar() 72 | except EOFError: 73 | result.eof = true 74 | 75 | method read(reader: FileReader): char = 76 | if reader.eof: 77 | raise newException(EOFError, "end of input file") 78 | result = reader.nextChar 79 | try: 80 | reader.nextChar = reader.file.readChar() 81 | except EOFError: 82 | reader.eof = true 83 | 84 | method peek(reader: FileReader): char = 85 | if reader.eof: 86 | result = '\0' 87 | else: 88 | result = reader.nextChar 89 | 90 | proc newScanner*(r: Reader): Scanner = 91 | result = Scanner(reader: r) 92 | 93 | proc toToken(s: string): Token = 94 | case toUpperAscii(s): 95 | of "ALL": 96 | return Token(kind: tokAll) 97 | of "AND": 98 | return Token(kind: tokAnd) 99 | of "ANY": 100 | return Token(kind: tokAny) 101 | of "AS": 102 | return Token(kind: tokAs) 103 | of "ASC": 104 | return Token(kind: tokAsc) 105 | of "AUTOINCREMENT", "AUTO_INCREMENT": 106 | return Token(kind: tokAutoincrement) 107 | of "BOTH": 108 | return Token(kind: tokBoth) 109 | of "BY": 110 | return Token(kind: tokBy) 111 | of "CASE": 112 | return Token(kind: tokCase) 113 | of "CAST": 114 | return Token(kind: tokCast) 115 | of "COMMIT": 116 | return Token(kind: tokCommit) 117 | of "COUNT": 118 | return Token(kind: tokCount) 119 | of "CHARACTER", "CHAR": 120 | return Token(kind: tokChar) 121 | of "CREATE": 122 | return Token(kind: tokCreate) 123 | of "CROSS": 124 | return Token(kind: tokCross) 125 | of "DEC", "DECIMAL": 126 | return Token(kind: tokDecimal) 127 | of "DELETE": 128 | return Token(kind: tokDelete) 129 | of "DEFAULT": 130 | return Token(kind: tokDefault) 131 | of "DESC": 132 | return Token(kind: tokDesc) 133 | of "DISTINCT": 134 | return Token(kind: tokDistinct) 135 | of "DOUBLE": 136 | return Token(kind: tokDouble) 137 | of "DROP": 138 | return Token(kind: tokDrop) 139 | of "ELSE": 140 | return Token(kind: tokElse) 141 | of "END": 142 | return Token(kind: tokEnd) 143 | of "EXCEPT": 144 | return Token(kind: tokExcept) 145 | of "EXISTS": 146 | return Token(kind: tokExists) 147 | of "FALSE": 148 | return Token(kind: tokFalse) 149 | of "GROUP": 150 | return Token(kind: tokGroup) 151 | of "TIME": 152 | return Token(kind: tokTime) 153 | of "TIMESTAMP": 154 | return Token(kind: tokTimestamp) 155 | of "THEN": 156 | return Token(kind: tokThen) 157 | of "TRUE": 158 | return Token(kind: tokTrue) 159 | of "FROM": 160 | return Token(kind: tokFrom) 161 | of "IF": 162 | return Token(kind: tokIf) 163 | of "INNER": 164 | return Token(kind: tokInner) 165 | of "INSERT": 166 | return Token(kind: tokInsert) 167 | of "IN": 168 | return Token(kind: tokIn) 169 | of "INTERSECT": 170 | return Token(kind: tokIntersect) 171 | of "INTO": 172 | return Token(kind: tokInto) 173 | of "IS": 174 | return Token(kind: tokIs) 175 | of "JOIN": 176 | return Token(kind: tokJoin) 177 | of "KEY": 178 | return Token(kind: tokKey) 179 | of "LEADING": 180 | return Token(kind: tokLeading) 181 | of "LEFT": 182 | return Token(kind: tokLeft) 183 | of "LIKE": 184 | return Token(kind: tokLike) 185 | of "NOT": 186 | return Token(kind: tokNot) 187 | of "NULL": 188 | return Token(kind: tokNull) 189 | of "NUMERIC": 190 | return Token(kind: tokNumeric) 191 | of "ON": 192 | return Token(kind: tokOn) 193 | of "OR": 194 | return Token(kind: tokOr) 195 | of "ORDER": 196 | return Token(kind: tokOrder) 197 | of "OUTER": 198 | return Token(kind: tokOuter) 199 | of "POSITION": 200 | return Token(kind: tokPosition) 201 | of "PRIMARY": 202 | return Token(kind: tokPrimary) 203 | of "PRECISION": 204 | return Token(kind: tokPrecision) 205 | of "TABLE": 206 | return Token(kind: tokTable) 207 | of "TRAILING": 208 | return Token(kind: tokTrailing) 209 | of "TRIM": 210 | return Token(kind: tokTrim) 211 | of "ROLLBACK": 212 | return Token(kind: tokRollback) 213 | of "SELECT": 214 | return Token(kind: tokSelect) 215 | of "SET": 216 | return Token(kind: tokSet) 217 | of "SOME": 218 | return Token(kind: tokAny) 219 | of "UNION": 220 | return Token(kind: tokUnion) 221 | of "UPDATE": 222 | return Token(kind: tokUpdate) 223 | of "VALUES": 224 | return Token(kind: tokValues) 225 | of "VARCHAR": 226 | return Token(kind: tokVarchar) 227 | of "WHEN": 228 | return Token(kind: tokWhen) 229 | of "WHERE": 230 | return Token(kind: tokWhere) 231 | of "WITH": 232 | return Token(kind: tokWith) 233 | result = Token(kind: tokIdentifier, identifier: toUpperAscii(s)) 234 | 235 | proc currentToken*(s: Scanner): Token = 236 | result = s.current 237 | 238 | func isAlphaNumericUnderscore(c: char): bool = 239 | result = isAlphaNumeric(c) or c == '_' 240 | 241 | proc readNextToken(s: Scanner): Token = 242 | var c: char 243 | try: 244 | c = s.reader.read() 245 | while isSpaceAscii(c): 246 | c = s.reader.read() 247 | except EOFError: 248 | return Token(kind: tokEndOfInput) 249 | if isAlphaAscii(c): 250 | var id = $c 251 | try: 252 | while isAlphaNumericUnderscore(s.reader.peek()): 253 | id &= s.reader.read() 254 | except EOFError: 255 | discard 256 | return toToken(id) 257 | if isDigit(c): 258 | var numStr = $c 259 | try: 260 | while isDigit(s.reader.peek()): 261 | numStr &= s.reader.read() 262 | if s.reader.peek() == '.': 263 | numStr &= "." 264 | discard s.reader.read() 265 | while isDigit(s.reader.peek()): 266 | numStr &= s.reader.read() 267 | if toUpperAscii(s.reader.peek()) == 'E': 268 | numStr &= 'E' 269 | discard s.reader.read() 270 | let sc = s.reader.peek() 271 | if sc == '+' or sc == '-': 272 | numStr &= sc 273 | discard s.reader.read() 274 | while isDigit(s.reader.peek()): 275 | numStr &= s.reader.read() 276 | except EOFError: 277 | discard 278 | return if find(numStr, ".") >= 0: Token(kind: tokRat, value: numStr) 279 | else: Token(kind: tokInt, value: numStr) 280 | case c: 281 | of '*': 282 | return Token(kind: tokAsterisk) 283 | of '/': 284 | return Token(kind: tokDiv) 285 | of '+': 286 | return Token(kind: tokPlus) 287 | of '-': 288 | return Token(kind: tokMinus) 289 | of '(': 290 | return Token(kind: tokLeftParen) 291 | of ')': 292 | return Token(kind: tokRightParen) 293 | of ',': 294 | return Token(kind: tokComma) 295 | of '.': 296 | return Token(kind: tokDot) 297 | of '=': 298 | return Token(kind: tokEq) 299 | of '<': 300 | if s.reader.peek() == '>': 301 | discard s.reader.read() 302 | return Token(kind: tokNeq) 303 | elif s.reader.peek() == '=': 304 | discard s.reader.read() 305 | return Token(kind: tokLe) 306 | return Token(kind: tokLt) 307 | of '>': 308 | if s.reader.peek() == '=': 309 | discard s.reader.read() 310 | return Token(kind: tokGe) 311 | return Token(kind: tokGt) 312 | of '|': 313 | if s.reader.read() != '|': 314 | raiseDbError("invalid operator: |", syntaxError) 315 | return Token(kind: tokConcat) 316 | of '\'': 317 | var str = "" 318 | while true: 319 | c = s.reader.read() 320 | if c == '\'': 321 | if s.reader.peek() == '\'': 322 | discard s.reader.read() 323 | str &= '\'' 324 | else: 325 | break 326 | else: 327 | str &= c 328 | return Token(kind: tokString, value: str) 329 | of '?': 330 | return Token(kind: tokPlaceholder) 331 | of '$': 332 | return Token(kind: tokNumPlaceholder) 333 | else: 334 | raiseDbError("Invalid character: " & c, syntaxError) 335 | 336 | proc nextToken*(s: Scanner): Token = 337 | s.current = readNextToken(s) 338 | result = s.current 339 | 340 | proc isValidTime*(str: string): bool = 341 | if str.len > 15: 342 | return false 343 | try: 344 | discard parse(str.substr(0, 7), "hh:mm:ss") 345 | except: 346 | return false 347 | if str.len > 8: 348 | if str[8] != '.': 349 | return false 350 | for i in 9.. 26: 357 | return false 358 | try: 359 | discard parse(str.substr(0, 18), "yyyy-MM-dd HH:mm:ss", utc()) 360 | except: 361 | return false 362 | if str.len > 19: 363 | if str[19] != '.': 364 | return false 365 | for i in 20..= rcols[i].typ.maxReprLen: lcols[i].typ.maxReprLen 65 | else: rcols[i].typ.maxReprLen, 66 | precision: if lcols[i].typ.precision >= rcols[i].typ.precision: lcols[i].typ.precision 67 | else: rcols[i].typ.precision, 68 | scale: if lcols[i].typ.scale >= rcols[i].typ.scale: lcols[i].typ.scale 69 | else: rcols[i].typ.scale, 70 | min: if lcols[i].typ.min <= rcols[i].typ.min: lcols[i].typ.min 71 | else: rcols[i].typ.min, 72 | max: if lcols[i].typ.min >= rcols[i].typ.min: lcols[i].typ.max 73 | else: rcols[i].typ.max, 74 | validValues: @[]) 75 | result.add(DbColumn(name: if lcols[i].name == rcols[i].name: lcols[i].name else: "", 76 | tableName: "", typ: typ, primaryKey: false, foreignKey: false)) 77 | -------------------------------------------------------------------------------- /tests/alltests.nim: -------------------------------------------------------------------------------- 1 | import osproc 2 | 3 | var failedTests: seq[string] 4 | 5 | proc execTest(testFile: string) = 6 | if execCmd("nim c -r " & testFile) != 0: 7 | failedTests.add(testFile) 8 | 9 | execTest("binary.nim") 10 | execTest("boolean.nim") 11 | execTest("char.nim") 12 | execTest("commit.nim") 13 | execTest("default.nim") 14 | execTest("distinct.nim") 15 | execTest("expjoin.nim") 16 | execTest("group.nim") 17 | execTest("impjoin.nim") 18 | execTest("leftjoin.nim") 19 | execTest("key.nim") 20 | execTest("like.nim") 21 | execTest("null.nim") 22 | execTest("numeric.nim") 23 | execTest("order.nim") 24 | execTest("prepared.nim") 25 | execTest("rollback.nim") 26 | execTest("snapshots.nim") 27 | execTest("subqueries.nim") 28 | execTest("union.nim") 29 | execTest("update.nim") 30 | execTest("where.nim") 31 | execTest("txlog.nim") 32 | execTest("txlog_snapshot.nim") 33 | execTest("datetime.nim") 34 | execTest("cast.nim") 35 | execTest("autoinc.nim") 36 | execTest("autoinc_txlog.nim") 37 | execTest("except.nim") 38 | execTest("intersect.nim") 39 | execTest("with.nim") 40 | execTest("insert_select.nim") 41 | 42 | if failedTests.len > 0: 43 | echo "FAILURE: tests failed: " & $failedTests 44 | -------------------------------------------------------------------------------- /tests/autoinc.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | var db = open("", "", "", "") 4 | exec(db, sql"""CREATE TABLE tst 5 | (k integer primary key autoincrement, n numeric, s text, i bigint not null autoincrement)""") 6 | 7 | doAssert execAffectedRows(db, sql"INSERT INTO tst (n, s) VALUES (2, 'Yo')") == 1 8 | doAssert execAffectedRows(db, sql"INSERT INTO tst (n, s) VALUES (5, 'Yaa')") == 1 9 | 10 | var res = getAllRows(db, sql"SELECT * FROM tst ORDER BY k") 11 | 12 | doAssert res.len == 2 13 | doAssert res[0][0] == "1" 14 | doAssert res[0][1] == "2" 15 | doAssert res[0][2] == "Yo" 16 | doAssert res[0][3] == "1" 17 | doAssert res[1][0] == "2" 18 | doAssert res[1][1] == "5" 19 | doAssert res[1][2] == "Yaa" 20 | doAssert res[1][3] == "2" 21 | 22 | save(db, "snapshot.dump") 23 | 24 | db = open("", "", "", "") 25 | restore(db, "snapshot.dump") 26 | 27 | doAssert execAffectedRows(db, sql"INSERT INTO tst (n, s) VALUES (6, 'Ji')") == 1 28 | 29 | exec(db, sql"CREATE TABLE tst2 (n numeric primary key, t text)") 30 | exec(db, sql"INSERT INTO tst2 VALUES (10, 'Ba')") 31 | exec(db, sql"INSERT INTO tst2 VALUES (11, 'Bbo')") 32 | 33 | exec(db, sql"INSERT INTO tst (n, s) SELECT * FROM tst2") 34 | 35 | res = getAllRows(db, sql"SELECT * FROM tst ORDER BY k") 36 | 37 | doAssert res.len == 5 38 | doAssert res[0][0] == "1" 39 | doAssert res[0][1] == "2" 40 | doAssert res[0][2] == "Yo" 41 | doAssert res[0][3] == "1" 42 | doAssert res[1][0] == "2" 43 | doAssert res[1][1] == "5" 44 | doAssert res[1][2] == "Yaa" 45 | doAssert res[1][3] == "2" 46 | doAssert res[2][0] == "3" 47 | doAssert res[2][1] == "6" 48 | doAssert res[2][2] == "Ji" 49 | doAssert res[2][3] == "3" 50 | doAssert res[3][0] == "4" 51 | doAssert res[3][1] == "10" 52 | doAssert res[3][2] == "Ba" 53 | doAssert res[3][3] == "4" 54 | doAssert res[4][0] == "5" 55 | doAssert res[4][1] == "11" 56 | doAssert res[4][2] == "Bbo" 57 | doAssert res[4][3] == "5" 58 | 59 | close(db) 60 | -------------------------------------------------------------------------------- /tests/autoinc_txlog.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import os 3 | 4 | removeDir("db") 5 | 6 | var db = open("db", "", "", "") 7 | exec(db, sql"""CREATE TABLE tst 8 | (n numeric, k bigint primary key autoincrement, s text, i int autoincrement)""") 9 | 10 | doAssert execAffectedRows(db, sql"INSERT INTO tst (n, s) VALUES (2, 'Yo')") == 1 11 | doAssert execAffectedRows(db, sql"INSERT INTO tst (n, s) VALUES (5, 'Yaa')") == 1 12 | 13 | var res = getAllRows(db, sql"SELECT * FROM tst ORDER BY k") 14 | 15 | doAssert res.len == 2 16 | doAssert res[0][0] == "2" 17 | doAssert res[0][1] == "1" 18 | doAssert res[0][2] == "Yo" 19 | doAssert res[0][3] == "1" 20 | doAssert res[1][0] == "5" 21 | doAssert res[1][1] == "2" 22 | doAssert res[1][2] == "Yaa" 23 | doAssert res[1][3] == "2" 24 | 25 | close(db) 26 | 27 | db = open("db", "", "", "") 28 | 29 | doAssert execAffectedRows(db, sql"INSERT INTO tst (n, s) VALUES (6, 'Ji')") == 1 30 | doAssert execAffectedRows(db, sql"INSERT INTO tst (n, s) VALUES (7, 'Yj')") == 1 31 | 32 | res = getAllRows(db, sql"SELECT * FROM tst ORDER BY k") 33 | 34 | doAssert res.len == 4 35 | doAssert res[0][0] == "2" 36 | doAssert res[0][1] == "1" 37 | doAssert res[0][2] == "Yo" 38 | doAssert res[0][3] == "1" 39 | doAssert res[1][0] == "5" 40 | doAssert res[1][1] == "2" 41 | doAssert res[1][2] == "Yaa" 42 | doAssert res[1][3] == "2" 43 | doAssert res[2][0] == "6" 44 | doAssert res[2][1] == "3" 45 | doAssert res[2][2] == "Ji" 46 | doAssert res[2][3] == "3" 47 | doAssert res[3][0] == "7" 48 | doAssert res[3][1] == "4" 49 | doAssert res[3][2] == "Yj" 50 | doAssert res[3][3] == "4" 51 | 52 | close(db) 53 | -------------------------------------------------------------------------------- /tests/binary.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"CREATE TABLE tst (a binary primary key, b bytea, c varbinary, d longvarbinary, e raw)") 5 | 6 | let s1 = "\x01\x02AB\xFE\xFF" 7 | let s2 = "\x01\x02\x00AB\xFE\xFF" 8 | let s3 = "\x00ab" 9 | let s4 = "xX\x00\x08\x09" 10 | let s5 = "\n\r\"" 11 | exec(db, sql"INSERT INTO tst VALUES (?, ?, ?, ?, ?)", s1, s2, s3, s4, s5) 12 | 13 | let row = getRow(db, sql"SELECT a, b, c, d, e FROM tst") 14 | 15 | doAssert row[0] == s1 16 | doAssert row[1] == s2 17 | doAssert row[1].len == 7 18 | doAssert row[2] == s3 19 | doAssert row[3] == s4 20 | doAssert row[4] == s5 21 | 22 | doAssert getValue(db, 23 | sql"""SELECT COUNT(*) 24 | FROM tst 25 | WHERE a = ?""", 26 | s1) == "1" 27 | 28 | close(db) 29 | -------------------------------------------------------------------------------- /tests/boolean.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import strutils 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"""CREATE TABLE tst 6 | (a int primary key, b boolean, c boolean)""") 7 | 8 | doAssert execAffectedRows(db, sql"INSERT INTO tst VALUES (1, TRUE, false)") == 1 9 | 10 | var rows = getAllRows(db, sql"SELECT b, c, b AND c, b OR c FROM tst") 11 | 12 | doAssert rows.len == 1 13 | doAssert rows[0][0] == "TRUE" 14 | doAssert rows[0][1] == "FALSE" 15 | doAssert rows[0][2] == "FALSE" 16 | doAssert rows[0][3] == "TRUE" 17 | -------------------------------------------------------------------------------- /tests/cast.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"""CREATE TABLE tst 6 | (k int PRIMARY KEY, n numeric(10, 1), s text)""") 7 | exec(db, sql"""INSERT INTO tst VALUES(1, 5.5, 'T')""") 8 | 9 | doAssert getValue(db, sql"""SELECT k + CAST ('2' AS INT) FROM tst""") == "3" 10 | doAssert getValue(db, sql"""SELECT k + CAST ('2' AS REAL) FROM tst""") == "3.0" 11 | doAssert getValue(db, sql"""SELECT k + CAST ('2' AS DOUBLE PRECISION) FROM tst""") == "3.0" 12 | doAssert getValue(db, sql"""SELECT k + CAST ('2' AS BIGINT) FROM tst""") == "3" 13 | doAssert getValue(db, sql"""SELECT CAST (n AS NUMERIC(4,2)) FROM tst""") == "5.50" 14 | doAssert getValue(db, sql"""SELECT ':' || CAST (n as TEXT) FROM tst""") == ":5.5" 15 | doAssert getValue(db, sql"""SELECT CAST (s || 'RUE' AS BOOLEAN) FROM tst""") == "TRUE" 16 | 17 | var cols: DbColumns 18 | var val: string 19 | for r in instantRows(db, cols, sql"""SELECT CAST(s || 'TX' AS CHAR(3)) FROM tst"""): 20 | val = r[0] 21 | 22 | doAssert val == "TTX" 23 | doAssert cols[0].typ.kind == dbFixedChar 24 | 25 | try: 26 | echo getValue(db, sql"""SELECT CAST(500 + n AS NUMERIC(1, 1)) FROM tst""") 27 | raiseAssert("CAST with insufficient precision succeeded") 28 | except DbError as e: 29 | doAssert sqlState(e) == "22003" 30 | try: 31 | echo getValue(db, sql"""SELECT CAST(s || 'TX' AS CHAR(2)) FROM tst""") 32 | raiseAssert("CAST with insufficient size succeeded") 33 | except DbError as e: 34 | doAssert sqlState(e) == "22001" 35 | 36 | exec(db, sql"""INSERT INTO tst VALUES(2, 5.5, '05:')""") 37 | 38 | var row = getRow(db, sql"""SELECT CAST(s || '10:12' AS TIME), 39 | CAST('2002-12-02' AS DATE), 40 | CAST('1902-02-03 ' || s || '01:03.223344' AS TIMESTAMP) 41 | FROM tst""") 42 | doAssert row[0] == "05:10:12" 43 | doAssert row[1] == "2002-12-02" 44 | doAssert row[2] == "1902-02-03 05:01:03.223344" 45 | 46 | row = getRow(db, sql"""SELECT CAST(s || '10:12.345' AS TIME(2)), 47 | CAST('2002-12-02' AS DATE), 48 | CAST('1902-02-03 ' || s || '01:03.223344' AS TIMESTAMP(5)) 49 | FROM tst""") 50 | doAssert row[0] == "05:10:12.34" 51 | doAssert row[1] == "2002-12-02" 52 | doAssert row[2] == "1902-02-03 05:01:03.22334" 53 | 54 | close(db) 55 | -------------------------------------------------------------------------------- /tests/char.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"CREATE TABLE tst (a char(3) primary key, b char, c varchar(5), d text)") 6 | 7 | try: 8 | exec(db, sql"INSERT INTO tst (a, c) VALUES (?, ?)", "t", "123456") 9 | raiseAssert("value exceeding column length was excepted") 10 | except DbError: 11 | discard 12 | 13 | exec(db, sql"INSERT INTO tst VALUES (?, 'f', 'Don''t ', ? || UPPER(?) || LOWER(?))", 14 | "yo", "Yo", "Yo", "Yo") 15 | 16 | var res: seq[seq[string]] 17 | 18 | var cols: DbColumns 19 | for r in instantRows(db, cols, sql"SELECT * FROM tst"): 20 | res.add(@[r[0], r[1], r[2], r[3]]) 21 | 22 | doAssert cols.len == 4 23 | doAssert cols[0].name == "A" 24 | doAssert cols[0].typ.kind == dbFixedChar 25 | doAssert cols[0].primaryKey 26 | doAssert cols[1].name == "B" 27 | doAssert cols[1].typ.kind == dbFixedChar 28 | doAssert not cols[1].primaryKey 29 | doAssert cols[2].name == "C" 30 | doAssert cols[2].typ.kind == dbVarchar 31 | doAssert not cols[2].primaryKey 32 | doAssert cols[3].name == "D" 33 | doAssert cols[3].typ.kind == dbVarchar 34 | doAssert not cols[3].primaryKey 35 | 36 | doAssert res.len == 1 37 | doAssert res[0][0] == "yo " 38 | doAssert res[0][1] == "f" 39 | doAssert res[0][2] == "Don't " 40 | doAssert res[0][3] == "YoYOyo" 41 | 42 | doAssert getValue(db, sql"SELECT SUBSTR(d, 2, 2) FROM tst") == "oY" 43 | doAssert getValue(db, sql"SELECT SUBSTR(d, ?) FROM tst", "2") == "oYOyo" 44 | doAssert getValue(db, sql"SELECT SUBSTR(d, -1, 1) FROM tst") == "o" 45 | doAssert getValue(db, sql"SELECT SUBSTR(d, -2 * 1) FROM tst") == "yo" 46 | 47 | doAssert getValue(db, sql"SELECT POSITION('Oy' IN d) FROM tst") == "4" 48 | doAssert getValue(db, sql"SELECT POSITION('' IN d) FROM tst") == "1" 49 | doAssert getValue(db, sql"SELECT POSITION('Bab' IN d) FROM tst") == "0" 50 | doAssert getValue(db, sql"SELECT POSITION('h' IN 'Äh') FROM tst") == "2" 51 | 52 | res = @[] 53 | for r in instantRows(db, sql"SELECT * FROM tst WHERE b IN (?)", "f"): 54 | res.add(@[r[0], r[1], r[2], r[3]]) 55 | 56 | doAssert res.len == 1 57 | doAssert res[0][0] == "yo " 58 | doAssert res[0][1] == "f" 59 | doAssert res[0][2] == "Don't " 60 | doAssert res[0][3] == "YoYOyo" 61 | 62 | doAssert getValue(db, sql"SELECT b FROM tst WHERE b >= ?", "f") == "f" 63 | 64 | exec(db, sql"UPDATE tst SET b = '', c = 'Do', d = d || d") 65 | 66 | res = @[] 67 | for r in instantRows(db, sql"SELECT * FROM tst"): 68 | res.add(@[r[0], r[1], r[2], r[3]]) 69 | 70 | doAssert res.len == 1 71 | doAssert res[0][0] == "yo " 72 | doAssert res[0][1] == " " 73 | doAssert res[0][2] == "Do" 74 | doAssert res[0][3] == "YoYOyoYoYOyo" 75 | 76 | doAssert getValue(db, sql"SELECT COUNT(*) FROM tst WHERE c >= 'Do'") == "1" 77 | 78 | doAssert getValue(db, sql"SELECT COUNT(*) FROM tst WHERE c > 'Do'") == "0" 79 | 80 | try: 81 | echo getValue(db, sql"SELECT COUNT(*) FROM tst WHERE c >= 3") 82 | raiseAssert("comparing character column with number succeeded") 83 | except DbError: 84 | discard 85 | 86 | doAssert getValue(db, sql"SELECT OCTET_LENGTH(c) FROM tst WHERE a = 'yo '") == "2" 87 | doAssert getValue(db, sql"SELECT LENGTH(c) FROM tst WHERE a = 'yo '") == "2" 88 | doAssert getValue(db, sql"SELECT CHAR_LENGTH(c) FROM tst WHERE a = 'yo '") == "2" 89 | 90 | doAssert getValue(db, sql"SELECT TRIM(a) FROM tst WHERE TRIM(a) = 'yo'") == "yo" 91 | doAssert getValue(db, sql"SELECT TRIM(LEADING FROM ' ' || a) FROM tst WHERE a = 'yo '") == "yo " 92 | doAssert getValue(db, sql"SELECT TRIM(TRAILING FROM ' ' || a) FROM tst WHERE a = 'yo '") == " yo" 93 | doAssert getValue(db, sql"SELECT TRIM(BOTH FROM ' ' || a) FROM tst WHERE a = 'yo '") == "yo" 94 | doAssert getValue(db, sql"SELECT TRIM('x' FROM 'xofx') FROM tst WHERE a = 'yo '") == "of" 95 | doAssert getValue(db, sql"SELECT TRIM(LEADING 'x' FROM 'xofx') FROM tst WHERE a = 'yo '") == "ofx" 96 | doAssert getValue(db, sql"SELECT TRIM(TRAILING 'x' FROM 'xofx') FROM tst WHERE a = 'yo '") == "xof" 97 | doAssert getValue(db, sql"SELECT TRIM(BOTH 'x' FROM 'xofx') FROM tst WHERE a = 'yo '") == "of" 98 | 99 | exec(db, sql"UPDATE tst SET c = '2' WHERE a = 'yo '") 100 | 101 | doAssert getValue(db, sql"SELECT COUNT(*) FROM tst WHERE c > ?", "10") == "1" 102 | 103 | exec(db, sql"DROP TABLE tst") 104 | 105 | try: 106 | for r in instantRows(db, sql"SELECT * FROM tst"): 107 | discard 108 | raiseAssert("tst is still accessible after DROP table") 109 | except DbError: 110 | doAssert sqlState((ref DbError)(getCurrentException())) == "42704" 111 | 112 | exec(db, sql"DROP TABLE IF EXISTS tst") 113 | -------------------------------------------------------------------------------- /tests/commit.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"CREATE TABLE tst (a int primary key, b int, c text)") 5 | exec(db, sql"INSERT INTO tst VALUES (1, 2, 'yo')") 6 | exec(db, sql"INSERT INTO tst VALUES (2, 3, 'ya')") 7 | 8 | db.setAutocommit(false) 9 | exec(db, sql"INSERT INTO tst VALUES (3, 3, 'yai')") 10 | 11 | exec(db, sql"UPDATE tst SET a = a + 10 WHERE b = 3") 12 | exec(db, sql"UPDATE tst SET c = 'yi' WHERE a = 1") 13 | 14 | exec(db, sql"DELETE FROM tst WHERE a = 12"); 15 | exec(db, sql"COMMIT") 16 | 17 | var rows = getAllRows(db, sql"SELECT * FROM tst ORDER BY a") 18 | doAssert rows.len == 2 19 | doAssert rows[0][0] == "1" 20 | doAssert rows[0][1] == "2" 21 | doAssert rows[0][2] == "yi" 22 | doAssert rows[1][0] == "13" 23 | doAssert rows[1][1] == "3" 24 | doAssert rows[1][2] == "yai" 25 | 26 | db.close() 27 | -------------------------------------------------------------------------------- /tests/datetime.nim: -------------------------------------------------------------------------------- 1 | import times 2 | import db_nimternalsql 3 | 4 | let db = open("", "", "", "") 5 | 6 | exec(db, sql"""CREATE TABLE dt (n int primary key, t time, t6 time(6), d date, 7 | ts timestamp, ts0 timestamp(0))""") 8 | 9 | exec(db, sql"""INSERT INTO dt VALUES(1, '09:01:02', '11:12:13.123456', '2021-12-23', 10 | '1993-06-13 22:59:59.123456', '2003-06-13 22:59:59')""") 11 | 12 | doAssert getValue(db, sql"""SELECT t FROM dt WHERE n = 1""") == "09:01:02" 13 | 14 | doAssert getValue(db, sql"""SELECT t6 FROM dt WHERE n = 1""") == "11:12:13.123456" 15 | 16 | doAssert getValue(db, sql"""SELECT d FROM dt WHERE n = 1""") == "2021-12-23" 17 | 18 | doAssert getValue(db, sql"""SELECT ts FROM dt WHERE n = 1""") == "1993-06-13 22:59:59.123456" 19 | 20 | doAssert getValue(db, sql"""SELECT ts0 FROM dt WHERE n = 1""") == "2003-06-13 22:59:59" 21 | 22 | doAssert getValue(db, sql"""SELECT t FROM dt WHERE t >= t""") == "09:01:02" 23 | doAssert getValue(db, sql"""SELECT t FROM dt WHERE t >= '09:01:02'""") == "09:01:02" 24 | doAssert getValue(db, sql"""SELECT t FROM dt WHERE '09:01:02' <= t""") == "09:01:02" 25 | doAssert getValue(db, sql"""SELECT t FROM dt WHERE t = t""") == "09:01:02" 26 | doAssert getValue(db, sql"""SELECT t FROM dt WHERE t = '09:01:02'""") == "09:01:02" 27 | doAssert getValue(db, sql"""SELECT t FROM dt WHERE '09:01:02' = t""") == "09:01:02" 28 | 29 | doAssert getValue(db, sql"""SELECT d FROM dt WHERE d >= d""") == "2021-12-23" 30 | doAssert getValue(db, sql"""SELECT d FROM dt WHERE d >= '2021-12-23'""") == "2021-12-23" 31 | doAssert getValue(db, sql"""SELECT d FROM dt WHERE '2021-12-23' <= d""") == "2021-12-23" 32 | doAssert getValue(db, sql"""SELECT d FROM dt WHERE d = d""") == "2021-12-23" 33 | doAssert getValue(db, sql"""SELECT d FROM dt WHERE d = '2021-12-23'""") == "2021-12-23" 34 | doAssert getValue(db, sql"""SELECT d FROM dt WHERE '2021-12-23' = d""") == "2021-12-23" 35 | 36 | doAssert getValue(db, sql"""SELECT ts FROM dt WHERE ts >= ts""") == "1993-06-13 22:59:59.123456" 37 | doAssert getValue(db, sql"""SELECT ts FROM dt WHERE ts <= ts""") == "1993-06-13 22:59:59.123456" 38 | doAssert getValue(db, sql"""SELECT ts FROM dt WHERE ts > ts""") == "" 39 | doAssert getValue(db, sql"""SELECT ts FROM dt WHERE ts < ts""") == "" 40 | doAssert getValue(db, sql"""SELECT ts FROM dt WHERE ts >= '1993-06-13 22:59:59.123456'""") == "1993-06-13 22:59:59.123456" 41 | doAssert getValue(db, sql"""SELECT ts FROM dt WHERE '1993-06-13 22:59:59.123456' >= ts """) == "1993-06-13 22:59:59.123456" 42 | doAssert getValue(db, sql"""SELECT ts FROM dt WHERE ts = ts""") == "1993-06-13 22:59:59.123456" 43 | doAssert getValue(db, sql"""SELECT ts FROM dt WHERE ts = '1993-06-13 22:59:59.123456'""") == "1993-06-13 22:59:59.123456" 44 | doAssert getValue(db, sql"""SELECT ts FROM dt WHERE '1993-06-13 22:59:59.123456' = ts """) == "1993-06-13 22:59:59.123456" 45 | 46 | exec(db, sql"INSERT INTO dt (n, t, d, ts) VALUES(2, current_time, current_date, current_timestamp)") 47 | 48 | discard parse(getValue(db, sql"""SELECT t FROM dt WHERE n = 2"""), "HH:mm:ss") 49 | 50 | var datestr = getValue(db, sql"""SELECT d FROM dt WHERE n = 2""") 51 | var dt = parse(datestr, "yyyy-MM-dd", utc()) 52 | doAssert dt.year == now().year 53 | doAssert dt.month == now().month 54 | doAssert dt.monthday == now().monthday 55 | 56 | datestr = getValue(db, sql"""SELECT ts FROM dt WHERE n = 2""") 57 | dt = parse(datestr, "yyyy-MM-dd HH:mm:ss'.'ffffff", utc()) 58 | doAssert dt.year == now().year 59 | doAssert dt.month == now().month 60 | doAssert dt.monthday == now().utc.monthday 61 | 62 | exec(db, sql"""CREATE TABLE dt2 (n int primary key, t time(3), ts timestamp(2))""") 63 | 64 | exec(db, sql"""INSERT INTO dt2 VALUES(1, '01:02:03.123456', '1993-06-13 20:21:22.123456')""") 65 | 66 | doAssert getValue(db, sql"""SELECT t FROM dt2""") == "01:02:03.123" 67 | 68 | doAssert getValue(db, sql"""SELECT t FROM dt2 WHERE t = '01:02:03.123'""") == "01:02:03.123" 69 | 70 | doAssert getValue(db, sql"""SELECT ts FROM dt2""") == "1993-06-13 20:21:22.12" 71 | 72 | doAssert getValue(db, sql"""SELECT ts FROM dt2 WHERE ts = '1993-06-13 20:21:22.12'""") == "1993-06-13 20:21:22.12" 73 | 74 | try: 75 | exec(db, sql"INSERT INTO dt (n, t) VALUES(3, TIME '05:06:7')") 76 | raiseAssert("invalid time literal accepted") 77 | except DbError as e: 78 | doAssert e.sqlState() == "22007" 79 | try: 80 | exec(db, sql"INSERT INTO dt (n, t) VALUES(3, TIME '05:06:07.f')") 81 | raiseAssert("invalid time literal accepted") 82 | except DbError as e: 83 | doAssert e.sqlState() == "22007" 84 | exec(db, sql"""INSERT INTO dt (n, t, ts, d) 85 | VALUES(3, TIME '05:06:08', TIMESTAMP '2000-01-02 05:04:06.123456', 86 | DATE '2003-02-01')""") 87 | 88 | let row = getRow(db, sql"SELECT t, ts, d FROM dt WHERE n = 3") 89 | doAssert row[0] == "05:06:08" 90 | doAssert row[1] == "2000-01-02 05:04:06.123456" 91 | doAssert row[2] == "2003-02-01" 92 | 93 | close(db) 94 | -------------------------------------------------------------------------------- /tests/default.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"""CREATE TABLE tst ( 5 | a char(3) DEFAULT 'nix' PRIMARY KEY, 6 | b char DEFAULT 'x' not null, 7 | c varchar(5))""") 8 | 9 | # Error 10 | try: 11 | exec(db, sql"INSERT INTO tst (a) VALUES('yay', 'Yo')") 12 | raiseAssert("INSERT succeeded although # of values differed from # of columns") 13 | except DbError as e: 14 | doAssert e.sqlState() == "42601" 15 | 16 | exec(db, sql"INSERT INTO tst (a, c) VALUES('yay', 'Yo')") 17 | exec(db, sql"INSERT INTO tst DEFAULT VALUES") 18 | 19 | var res: seq[seq[string]] 20 | 21 | for r in instantRows(db, sql"SELECT * FROM tst ORDER BY a"): 22 | res.add(@[r[0], r[1], r[2]]) 23 | 24 | doAssert res.len == 2 25 | doAssert res[0][0] == "nix" 26 | doAssert res[0][1] == "x" 27 | doAssert res[0][2] == "" 28 | doAssert res[1][0] == "yay" 29 | doAssert res[1][1] == "x" 30 | doAssert res[1][2] == "Yo" 31 | -------------------------------------------------------------------------------- /tests/delete.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"CREATE TABLE tst (a int primary key, b int, c text)") 5 | exec(db, sql"INSERT INTO tst VALUES (1, 2, 'yo')") 6 | exec(db, sql"INSERT INTO tst VALUES (2, 3, 'ya')") 7 | exec(db, sql"INSERT INTO tst VALUES (3, 3, 'yayo')") 8 | exec(db, sql"INSERT INTO tst VALUES (4, 10, 'yo')") 9 | 10 | doAssert execAffectedRows(db, sql"DELETE FROM tst WHERE a = 1") == 1 11 | 12 | var res: seq[seq[string]] 13 | for r in instantRows(db, sql"SELECT * FROM tst ORDER BY a"): 14 | res.add(@[r[0], r[1], r[2]]) 15 | 16 | doAssert res.len == 3 17 | doAssert res[0][0] == "2" 18 | doAssert res[0][1] == "3" 19 | doAssert res[0][2] == "ya" 20 | doAssert res[1][0] == "3" 21 | doAssert res[1][1] == "3" 22 | doAssert res[1][2] == "yayo" 23 | doAssert res[2][0] == "4" 24 | doAssert res[2][1] == "10" 25 | doAssert res[2][2] == "yo" 26 | 27 | doAssert execAffectedRows(db, sql"DELETE FROM tst WHERE c='yo'") == 1 28 | 29 | res = @[] 30 | for r in instantRows(db, sql"SELECT * FROM tst ORDER BY a"): 31 | res.add(@[r[0], r[1], r[2]]) 32 | doAssert res.len == 2 33 | doAssert res[0][0] == "2" 34 | doAssert res[0][1] == "3" 35 | doAssert res[0][2] == "ya" 36 | doAssert res[1][0] == "3" 37 | doAssert res[1][1] == "3" 38 | doAssert res[1][2] == "yayo" 39 | 40 | doAssert execAffectedRows(db, sql"DELETE FROM tst") == 2 41 | 42 | doAssert getValue(db, sql"SELECT COUNT(*) FROM tst") == "0" 43 | -------------------------------------------------------------------------------- /tests/distinct.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import algorithm 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"CREATE TABLE tst (a int primary key, b text, c varchar(2))") 6 | 7 | exec(db, sql"INSERT INTO tst VALUES (1, 'Fritz', 'ui')") 8 | exec(db, sql"INSERT INTO tst VALUES (2, 'Fritz', 'ui')") 9 | exec(db, sql"INSERT INTO tst VALUES (3, 'Fritz', 'uh')") 10 | exec(db, sql"INSERT INTO tst VALUES (4, 'Fritz', 'ui')") 11 | 12 | var rows = getAllRows(db, sql"SELECT DISTINCT b, c FROM tst ORDER BY c") 13 | doAssert rows.len == 2 14 | doAssert rows[0][0] == "Fritz" 15 | doAssert rows[0][1] == "uh" 16 | doAssert rows[1][0] == "Fritz" 17 | doAssert rows[1][1] == "ui" 18 | 19 | rows = getAllRows(db, sql"SELECT DISTINCT b, c FROM tst") 20 | rows.sort(proc(r1, r2: Row): int = 21 | result = cmp(r1[1], r2[1])) 22 | doAssert rows.len == 2 23 | doAssert rows[0][0] == "Fritz" 24 | doAssert rows[0][1] == "uh" 25 | doAssert rows[1][0] == "Fritz" 26 | doAssert rows[1][1] == "ui" 27 | 28 | exec(db, sql"INSERT INTO tst VALUES (5, 'Fritz', 'uh')") 29 | exec(db, sql"INSERT INTO tst VALUES (6, 'Fritz', 'ui')") 30 | 31 | rows = getAllRows(db, sql"SELECT DISTINCT b, c FROM tst ORDER BY b") 32 | rows.sort(proc(r1, r2: Row): int = 33 | result = cmp(r1[1], r2[1])) 34 | doAssert rows.len == 2 35 | doAssert rows[0][0] == "Fritz" 36 | doAssert rows[0][1] == "uh" 37 | doAssert rows[1][0] == "Fritz" 38 | doAssert rows[1][1] == "ui" 39 | 40 | rows = getAllRows(db, sql"SELECT DISTINCT b, c FROM tst ORDER BY b, c DESC") 41 | doAssert rows.len == 2 42 | doAssert rows[0][0] == "Fritz" 43 | doAssert rows[0][1] == "ui" 44 | doAssert rows[1][0] == "Fritz" 45 | doAssert rows[1][1] == "uh" 46 | -------------------------------------------------------------------------------- /tests/except.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"CREATE TABLE tst (a int, b text, c int primary key)") 6 | exec(db, sql"CREATE TABLE tst2 (a int, b text, c int, primary key(c, b))") 7 | exec(db, sql"INSERT INTO tst VALUES (1, 'ace', 1)") 8 | exec(db, sql"INSERT INTO tst VALUES (2, 'king', 2)") 9 | exec(db, sql"INSERT INTO tst VALUES (2, 'jack', 3)") 10 | exec(db, sql"INSERT INTO tst2 VALUES (2, 'king', 2)") 11 | exec(db, sql"INSERT INTO tst2 VALUES (3, 'queen', 2)") 12 | exec(db, sql"INSERT INTO tst2 VALUES (4, 'jack', 4)") 13 | 14 | var rows: seq[seq[string]] 15 | var cols: DbColumns 16 | 17 | for r in instantRows(db, cols, 18 | sql"""SELECT * FROM tst 19 | EXCEPT 20 | SELECT * FROM tst2 21 | ORDER BY c"""): 22 | rows.add(@[r[0], r[1], r[2]]) 23 | 24 | doAssert cols.len == 3 25 | doAssert cols[0].name == "A" 26 | doAssert cols[0].typ.kind == dbInt 27 | doAssert cols[1].name == "B" 28 | doAssert cols[1].typ.kind == dbVarchar 29 | doAssert cols[2].name == "C" 30 | doAssert cols[2].typ.kind == dbInt 31 | 32 | doAssert rows.len == 2 33 | doAssert rows[0][0] == "1" 34 | doAssert rows[0][1] == "ace" 35 | doAssert rows[0][2] == "1" 36 | doAssert rows[1][0] == "2" 37 | doAssert rows[1][1] == "jack" 38 | doAssert rows[1][2] == "3" 39 | 40 | rows = getAllRows(db, sql"""SELECT * FROM tst2 41 | EXCEPT 42 | SELECT * FROM tst 43 | ORDER BY a""") 44 | 45 | doAssert rows.len == 2 46 | doAssert rows[0][0] == "3" 47 | doAssert rows[0][1] == "queen" 48 | doAssert rows[1][0] == "4" 49 | doAssert rows[1][1] == "jack" 50 | 51 | rows = getAllRows(db, sql"""SELECT a, b FROM tst 52 | EXCEPT 53 | SELECT a, b FROM tst2 54 | ORDER BY a""") 55 | 56 | doAssert rows.len == 2 57 | doAssert rows[0][0] == "1" 58 | doAssert rows[0][1] == "ace" 59 | doAssert rows[1][0] == "2" 60 | doAssert rows[1][1] == "jack" 61 | 62 | rows = getAllRows(db, sql"""SELECT c FROM tst2 63 | EXCEPT 64 | SELECT c * 2 FROM tst 65 | WHERE c = 2 66 | ORDER BY c""") 67 | 68 | doAssert rows.len == 1 69 | doAssert rows[0][0] == "2" 70 | 71 | rows = getAllRows(db, sql"""SELECT c FROM tst2 72 | EXCEPT ALL 73 | SELECT 4 FROM tst 74 | ORDER BY c""") 75 | 76 | doAssert rows.len == 2 77 | doAssert rows[0][0] == "2" 78 | doAssert rows[1][0] == "2" 79 | -------------------------------------------------------------------------------- /tests/expjoin.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"CREATE TABLE emp (empno int primary key, firstName text not null, last_name text)") 5 | exec(db, sql"CREATE TABLE emp_team (empno int, team_name text, primary key (empno, team_name))") 6 | exec(db, sql"CREATE TABLE emp2 (no int primary key, firstName text not null, last_name text)") 7 | 8 | exec(db, sql"INSERT INTO emp VALUES(1, 'Bob', 'Base')") 9 | exec(db, sql"INSERT INTO emp VALUES(2, 'Daisy', 'Database')") 10 | exec(db, sql"INSERT INTO emp_team VALUES(1, 'Team A')") 11 | exec(db, sql"INSERT INTO emp_team VALUES(2, 'Team B')") 12 | exec(db, sql"INSERT INTO emp2 VALUES(1, 'Bob', 'Base')") 13 | 14 | var rows = getAllRows(db, 15 | sql"""SELECT * FROM emp 16 | CROSS JOIN emp_team 17 | ORDER BY emp.empno, emp_team.empno""") 18 | doAssert rows.len == 4 19 | doAssert rows[0][0] == "1" 20 | doAssert rows[0][1] == "Bob" 21 | doAssert rows[0][2] == "Base" 22 | doAssert rows[0][3] == "1" 23 | doAssert rows[0][4] == "Team A" 24 | doAssert rows[1][0] == "1" 25 | doAssert rows[1][1] == "Bob" 26 | doAssert rows[1][2] == "Base" 27 | doAssert rows[1][3] == "2" 28 | doAssert rows[1][4] == "Team B" 29 | doAssert rows[2][0] == "2" 30 | doAssert rows[2][1] == "Daisy" 31 | doAssert rows[2][2] == "Database" 32 | doAssert rows[2][3] == "1" 33 | doAssert rows[2][4] == "Team A" 34 | doAssert rows[3][0] == "2" 35 | doAssert rows[3][1] == "Daisy" 36 | doAssert rows[3][2] == "Database" 37 | doAssert rows[3][3] == "2" 38 | doAssert rows[3][4] == "Team B" 39 | 40 | rows = getAllRows(db, 41 | sql"""SELECT * FROM emp 42 | CROSS JOIN emp_team t1 CROSS JOIN emp_team t2 43 | WHERE emp.empno = t1.empno and t1.empno = t2.empno 44 | ORDER BY emp.empno""") 45 | doAssert rows.len == 2 46 | doAssert rows[0][0] == "1" 47 | doAssert rows[0][1] == "Bob" 48 | doAssert rows[0][2] == "Base" 49 | doAssert rows[0][3] == "1" 50 | doAssert rows[0][4] == "Team A" 51 | doAssert rows[1][0] == "2" 52 | doAssert rows[1][1] == "Daisy" 53 | doAssert rows[1][2] == "Database" 54 | doAssert rows[1][3] == "2" 55 | doAssert rows[1][4] == "Team B" 56 | 57 | rows = getAllRows(db, sql"""SELECT * FROM emp_team t 58 | JOIN emp ON t.empno = emp.empno 59 | ORDER BY last_name""") 60 | doAssert rows.len == 2 61 | doAssert rows[0][0] == "1" 62 | doAssert rows[0][1] == "Team A" 63 | doAssert rows[0][2] == "1" 64 | doAssert rows[0][3] == "Bob" 65 | doAssert rows[0][4] == "Base" 66 | doAssert rows[1][0] == "2" 67 | doAssert rows[1][1] == "Team B" 68 | doAssert rows[1][2] == "2" 69 | doAssert rows[1][3] == "Daisy" 70 | doAssert rows[1][4] == "Database" 71 | 72 | rows = getAllRows(db, sql"""SELECT * FROM emp2 INNER JOIN emp_team t 73 | ON no = empno 74 | ORDER BY last_name""") 75 | doAssert rows.len == 1 76 | doAssert rows[0][0] == "1" 77 | doAssert rows[0][1] == "Bob" 78 | doAssert rows[0][2] == "Base" 79 | doAssert rows[0][3] == "1" 80 | doAssert rows[0][4] == "Team A" 81 | 82 | # OUTER JOIN is not supported 83 | try: 84 | rows = getAllRows(db, sql"""SELECT * FROM emp_team t 85 | OUTER JOIN emp ON t.empno = emp.empno 86 | ORDER BY last_name""") 87 | raiseAssert("OUTER JOIN succeeded") 88 | except DbError: 89 | discard 90 | -------------------------------------------------------------------------------- /tests/group.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"CREATE TABLE tst (a int primary key, c text, rank text)") 6 | 7 | var rows = getAllRows(db, sql"SELECT COUNT(*), MAX(a), SUM(a), AVG(a) FROM tst") 8 | doAssert rows.len == 1 9 | doAssert rows[0][0] == "0" 10 | doAssert rows[0][1] == "" 11 | doAssert rows[0][2] == "" 12 | doAssert rows[0][3] == "" 13 | 14 | exec(db, sql"INSERT INTO tst VALUES (1, 'y', 'Ace')") 15 | exec(db, sql"INSERT INTO tst VALUES (2, 'x', 'King')") 16 | exec(db, sql"INSERT INTO tst VALUES (3, 'z', 'Queen')") 17 | exec(db, sql"INSERT INTO tst VALUES (4, 'x', 'Jack')") 18 | exec(db, sql"INSERT INTO tst VALUES (5, 'y', 'Ace')") 19 | exec(db, sql"INSERT INTO tst VALUES (6, 'y', 'Ace')") 20 | exec(db, sql"INSERT INTO tst VALUES (7, 'z', 'Queen')") 21 | 22 | doAssert getValue(db, sql"SELECT COUNT(*) FROM tst") == "7" 23 | 24 | rows = @[] 25 | var cols: DbColumns 26 | for r in instantRows(db, cols, 27 | sql"""SELECT c, rank, COUNT(*), MAX(a) AS MA, MIN(t.a), SUM(a), AVG(a) 28 | FROM tst t 29 | GROUP BY rank, c 30 | ORDER BY c"""): 31 | rows.add(@[r[0], r[1], r[2], r[3], r[4], r[5], r[6]]) 32 | 33 | doAssert cols.len == 7 34 | doAssert cols[0].name == "C" 35 | doAssert cols[0].typ.kind == dbVarchar 36 | doAssert cols[1].name == "RANK" 37 | doAssert cols[1].typ.kind == dbVarchar 38 | doAssert cols[2].name == "" 39 | doAssert cols[2].typ.kind == dbInt 40 | doAssert cols[3].name == "MA" 41 | doAssert cols[3].typ.kind == dbInt 42 | doAssert cols[4].name == "" 43 | doAssert cols[4].typ.kind == dbInt 44 | doAssert cols[5].name == "" 45 | doAssert cols[5].typ.kind == dbInt 46 | doAssert cols[6].name == "" 47 | doAssert cols[6].typ.kind == dbFloat 48 | 49 | doAssert rows.len == 4 50 | doAssert rows[0][0] == "x" 51 | doAssert rows[0][1] == "King" 52 | doAssert rows[0][2] == "1" 53 | doAssert rows[0][3] == "2" 54 | doAssert rows[0][4] == "2" 55 | doAssert rows[0][5] == "2" 56 | doAssert rows[0][6] == "2.0" 57 | doAssert rows[1][0] == "x" 58 | doAssert rows[1][1] == "Jack" 59 | doAssert rows[1][2] == "1" 60 | doAssert rows[1][3] == "4" 61 | doAssert rows[1][4] == "4" 62 | doAssert rows[1][5] == "4" 63 | doAssert rows[1][6] == "4.0" 64 | doAssert rows[2][0] == "y" 65 | doAssert rows[2][1] == "Ace" 66 | doAssert rows[2][2] == "3" 67 | doAssert rows[2][3] == "6" 68 | doAssert rows[2][4] == "6" 69 | doAssert rows[2][5] == "12" 70 | doAssert rows[2][6] == "4.0" 71 | doAssert rows[3][0] == "z" 72 | doAssert rows[3][1] == "Queen" 73 | doAssert rows[3][2] == "2" 74 | doAssert rows[3][3] == "7" 75 | doAssert rows[3][4] == "7" 76 | doAssert rows[3][5] == "10" 77 | doAssert rows[3][6] == "5.0" 78 | 79 | rows = getAllRows(db, sql"""SELECT COUNT(*), MAX(a), c, rank r 80 | FROM tst t 81 | GROUP BY c, r 82 | ORDER BY r""") 83 | doAssert rows.len == 4 84 | doAssert rows[0][0] == "3" 85 | doAssert rows[0][1] == "6" 86 | doAssert rows[0][2] == "y" 87 | doAssert rows[0][3] == "Ace" 88 | doAssert rows[1][0] == "1" 89 | doAssert rows[1][1] == "4" 90 | doAssert rows[1][2] == "x" 91 | doAssert rows[1][3] == "Jack" 92 | doAssert rows[2][0] == "1" 93 | doAssert rows[2][1] == "2" 94 | doAssert rows[2][2] == "x" 95 | doAssert rows[2][3] == "King" 96 | doAssert rows[3][0] == "2" 97 | doAssert rows[3][1] == "7" 98 | doAssert rows[3][2] == "z" 99 | doAssert rows[3][3] == "Queen" 100 | 101 | rows = getAllRows(db, sql"""SELECT rank r, COUNT(*), MAX(a), c 102 | FROM tst t 103 | WHERE a < ? 104 | GROUP BY c, r 105 | ORDER BY c""", 106 | "8") 107 | doAssert rows.len == 4 108 | doAssert rows[0][0] == "King" 109 | doAssert rows[0][1] == "1" 110 | doAssert rows[0][2] == "2" 111 | doAssert rows[0][3] == "x" 112 | doAssert rows[1][0] == "Jack" 113 | doAssert rows[1][1] == "1" 114 | doAssert rows[1][2] == "4" 115 | doAssert rows[1][3] == "x" 116 | doAssert rows[2][0] == "Ace" 117 | doAssert rows[2][1] == "3" 118 | doAssert rows[2][2] == "6" 119 | doAssert rows[2][3] == "y" 120 | doAssert rows[3][0] == "Queen" 121 | doAssert rows[3][1] == "2" 122 | doAssert rows[3][2] == "7" 123 | doAssert rows[3][3] == "z" 124 | 125 | rows = getAllRows(db, sql"""SELECT a, c, rank 126 | FROM tst 127 | GROUP BY a, c, rank 128 | ORDER BY a""") 129 | 130 | doAssert rows.len == 7 131 | doAssert rows[0][0] == "1" 132 | doAssert rows[0][1] == "y" 133 | doAssert rows[0][2] == "Ace" 134 | doAssert rows[1][0] == "2" 135 | doAssert rows[1][1] == "x" 136 | doAssert rows[1][2] == "King" 137 | doAssert rows[2][0] == "3" 138 | doAssert rows[2][1] == "z" 139 | doAssert rows[2][2] == "Queen" 140 | doAssert rows[3][0] == "4" 141 | doAssert rows[3][1] == "x" 142 | doAssert rows[3][2] == "Jack" 143 | doAssert rows[4][0] == "5" 144 | doAssert rows[4][1] == "y" 145 | doAssert rows[4][2] == "Ace" 146 | doAssert rows[5][0] == "6" 147 | doAssert rows[5][1] == "y" 148 | doAssert rows[5][2] == "Ace" 149 | doAssert rows[6][0] == "7" 150 | doAssert rows[6][1] == "z" 151 | doAssert rows[6][2] == "Queen" 152 | 153 | try: 154 | rows = getAllRows(db, sql"""SELECT a, c, rank 155 | FROM tst 156 | GROUP BY c, rank 157 | ORDER BY a""") 158 | raiseAssert("invalid grouping succeeded") 159 | except DbError as e: 160 | doAssert sqlState(e) == "42803" 161 | 162 | rows = getAllRows(db, sql"""SELECT * 163 | FROM tst 164 | GROUP BY a, c, rank 165 | ORDER BY a""") 166 | 167 | doAssert rows.len == 7 168 | doAssert rows[0][0] == "1" 169 | doAssert rows[0][1] == "y" 170 | doAssert rows[0][2] == "Ace" 171 | doAssert rows[1][0] == "2" 172 | doAssert rows[1][1] == "x" 173 | doAssert rows[1][2] == "King" 174 | doAssert rows[2][0] == "3" 175 | doAssert rows[2][1] == "z" 176 | doAssert rows[2][2] == "Queen" 177 | doAssert rows[3][0] == "4" 178 | doAssert rows[3][1] == "x" 179 | doAssert rows[3][2] == "Jack" 180 | doAssert rows[4][0] == "5" 181 | doAssert rows[4][1] == "y" 182 | doAssert rows[4][2] == "Ace" 183 | doAssert rows[5][0] == "6" 184 | doAssert rows[5][1] == "y" 185 | doAssert rows[5][2] == "Ace" 186 | doAssert rows[6][0] == "7" 187 | doAssert rows[6][1] == "z" 188 | doAssert rows[6][2] == "Queen" 189 | 190 | try: 191 | rows = getAllRows(db, sql"""SELECT * 192 | FROM tst 193 | GROUP BY c, rank 194 | ORDER BY a""") 195 | raiseAssert("invalid grouping succeeded") 196 | except DbError as e: 197 | doAssert sqlState(e) == "42803" 198 | 199 | exec(db, sql"CREATE TABLE tst2 (a int primary key, b int, rank text)") 200 | 201 | exec(db, sql"INSERT INTO tst2 VALUES (1, 1, 'Jack')") 202 | exec(db, sql"INSERT INTO tst2 VALUES (2, 1, 'Ace')") 203 | exec(db, sql"INSERT INTO tst2 VALUES (3, 1, 'King')") 204 | exec(db, sql"INSERT INTO tst2 VALUES (4, 2, 'Queen')") 205 | exec(db, sql"INSERT INTO tst2 VALUES (5, 2, 'Jack')") 206 | 207 | rows = getAllRows(db, sql"""SELECT b, MIN(rank), MAX(rank) 208 | FROM tst2 209 | GROUP BY b 210 | ORDER BY b""") 211 | doAssert rows.len == 2 212 | doAssert rows[0][0] == "1" 213 | doAssert rows[0][1] == "Ace" 214 | doAssert rows[0][2] == "King" 215 | doAssert rows[1][0] == "2" 216 | doAssert rows[1][1] == "Jack" 217 | doAssert rows[1][2] == "Queen" 218 | -------------------------------------------------------------------------------- /tests/impjoin.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"CREATE TABLE test1 (a text not null, b text, c int primary key)") 6 | exec(db, sql"CREATE TABLE test2 (d text, e int primary key)") 7 | 8 | exec(db, sql"INSERT INTO test1 VALUES('Pitch', 'P', 1)") 9 | exec(db, sql"INSERT INTO test1 VALUES('Pitsh', 'Px', 2)") 10 | exec(db, sql"INSERT INTO test2 VALUES('Sulphur', 1)") 11 | exec(db, sql"INSERT INTO test2 VALUES('Sulfur', 2)") 12 | 13 | var rows: seq[seq[string]] 14 | 15 | var cols: DbColumns 16 | for r in instantRows(db, cols, 17 | sql"""SELECT * FROM test1, test2 t2 18 | WHERE test1.c = t2.e 19 | ORDER BY a"""): 20 | rows.add(@[r[0], r[1], r[2], r[3]]) 21 | 22 | doAssert cols.len == 5 23 | doAssert cols[0].name == "A" 24 | doAssert cols[0].tableName == "TEST1" 25 | doAssert cols[0].typ.kind == dbVarchar 26 | doAssert cols[1].name == "B" 27 | doAssert cols[1].tableName == "TEST1" 28 | doAssert cols[1].typ.kind == dbVarchar 29 | doAssert cols[2].name == "C" 30 | doAssert cols[2].tableName == "TEST1" 31 | doAssert cols[2].typ.kind == dbInt 32 | doAssert cols[3].name == "D" 33 | doAssert cols[3].tableName == "TEST2" 34 | doAssert cols[3].typ.kind == dbVarchar 35 | doAssert cols[4].name == "E" 36 | doAssert cols[4].tableName == "TEST2" 37 | doAssert cols[4].typ.kind == dbInt 38 | 39 | doAssert rows.len == 2 40 | 41 | rows = getAllRows(db, 42 | sql"""SELECT * FROM test2 t2, test1 43 | WHERE test1.c = t2.e 44 | ORDER BY e""") 45 | doAssert rows.len == 2 46 | doAssert rows[0][0] == "Sulphur" 47 | doAssert rows[0][1] == "1" 48 | doAssert rows[0][2] == "Pitch" 49 | doAssert rows[0][3] == "P" 50 | doAssert rows[0][4] == "1" 51 | doAssert rows[1][0] == "Sulfur" 52 | doAssert rows[1][1] == "2" 53 | doAssert rows[1][2] == "Pitsh" 54 | doAssert rows[1][3] == "Px" 55 | doAssert rows[1][4] == "2" 56 | 57 | rows = getAllRows(db, 58 | sql"""SELECT * FROM test1, test2 t2, test2 t3 59 | WHERE test1.c = t2.e AND t2.e = t3.e 60 | ORDER BY c, t2.e, t3.e""") 61 | doAssert rows.len == 4 62 | doAssert rows[0][0] == "Pitch" 63 | doAssert rows[0][1] == "P" 64 | doAssert rows[0][2] == "1" 65 | doAssert rows[0][3] == "Sulphur" 66 | doAssert rows[0][4] == "1" 67 | doAssert rows[0][5] == "Sulphur" 68 | doAssert rows[0][6] == "1" 69 | doAssert rows[1][0] == "Pitch" 70 | doAssert rows[1][1] == "P" 71 | doAssert rows[1][2] == "1" 72 | doAssert rows[1][3] == "Sulfur" 73 | doAssert rows[1][4] == "2" 74 | doAssert rows[1][5] == "Sulfur" 75 | doAssert rows[1][6] == "2" 76 | doAssert rows[2][0] == "Pitsh" 77 | doAssert rows[2][1] == "Px" 78 | doAssert rows[2][2] == "2" 79 | doAssert rows[2][3] == "Sulphur" 80 | doAssert rows[2][4] == "1" 81 | doAssert rows[2][5] == "Sulphur" 82 | doAssert rows[2][6] == "1" 83 | doAssert rows[3][0] == "Pitsh" 84 | doAssert rows[3][1] == "Px" 85 | doAssert rows[3][2] == "2" 86 | doAssert rows[3][3] == "Sulfur" 87 | doAssert rows[3][4] == "2" 88 | doAssert rows[3][5] == "Sulfur" 89 | doAssert rows[3][6] == "2" 90 | 91 | try: 92 | rows = getAllRows(db, sql"""SELECT * FROM test1, test2 t2, test2 t3 93 | WHERE test1.c = t2.e and t2.e = e""") 94 | raiseAssert("SELECT with ambiguous column refs succeeded") 95 | except DbError: 96 | discard 97 | -------------------------------------------------------------------------------- /tests/insert_select.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"CREATE TABLE tst (a int primary key, b char, c text)") 6 | 7 | exec(db, sql"INSERT INTO tst VALUES (1, 'a', 'Alpha')") 8 | exec(db, sql"INSERT INTO tst VALUES (2, 'b', 'Beta')") 9 | exec(db, sql"INSERT INTO tst VALUES (3, 'g', 'Gamma')") 10 | 11 | exec(db, sql"CREATE TABLE tst2 (b char primary key, c text)") 12 | 13 | doAssert execAffectedRows(db, sql"INSERT INTO tst2 SELECT b, c FROM tst") == 3 14 | 15 | var rows = getAllRows(db, sql"SELECT * FROM tst2 ORDER BY c") 16 | doAssert rows[0][0] == "a" 17 | doAssert rows[0][1] == "Alpha" 18 | doAssert rows[1][0] == "b" 19 | doAssert rows[1][1] == "Beta" 20 | doAssert rows[2][0] == "g" 21 | doAssert rows[2][1] == "Gamma" 22 | 23 | exec(db, sql"CREATE TABLE tst3 (x char primary key, y text)") 24 | 25 | doAssert execAffectedRows(db, sql"INSERT INTO tst3 (y, x) SELECT c, b FROM tst") == 3 26 | 27 | rows = getAllRows(db, sql"SELECT * FROM tst3 ORDER BY y") 28 | doAssert rows[0][0] == "a" 29 | doAssert rows[0][1] == "Alpha" 30 | doAssert rows[1][0] == "b" 31 | doAssert rows[1][1] == "Beta" 32 | doAssert rows[2][0] == "g" 33 | doAssert rows[2][1] == "Gamma" 34 | 35 | exec(db, sql"CREATE TABLE tst4 (y text default '-', x char primary key)") 36 | 37 | doAssert execAffectedRows(db, 38 | sql"INSERT INTO tst4 (x) SELECT b FROM tst WHERE b > ?", 39 | "g" 40 | ) == 0 41 | 42 | rows = getAllRows(db, sql"SELECT * FROM tst4 ORDER BY x") 43 | doAssert rows.len == 0 44 | 45 | doAssert execAffectedRows(db, sql"INSERT INTO tst4 (x) SELECT b FROM tst") == 3 46 | 47 | rows = getAllRows(db, sql"SELECT * FROM tst4 ORDER BY x") 48 | doAssert rows.len == 3 49 | doAssert rows[0][0] == "-" 50 | doAssert rows[0][1] == "a" 51 | doAssert rows[1][0] == "-" 52 | doAssert rows[1][1] == "b" 53 | doAssert rows[2][0] == "-" 54 | doAssert rows[2][1] == "g" 55 | 56 | close(db) 57 | -------------------------------------------------------------------------------- /tests/intersect.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"CREATE TABLE tst (a int, b text, c int primary key)") 6 | exec(db, sql"CREATE TABLE tst2 (a int, b text, c int, primary key(c, b))") 7 | exec(db, sql"INSERT INTO tst VALUES (1, 'ace', 1)") 8 | exec(db, sql"INSERT INTO tst VALUES (2, 'king', 2)") 9 | exec(db, sql"INSERT INTO tst VALUES (2, 'jack', 3)") 10 | exec(db, sql"INSERT INTO tst2 VALUES (2, 'king', 2)") 11 | exec(db, sql"INSERT INTO tst2 VALUES (3, 'queen', 2)") 12 | exec(db, sql"INSERT INTO tst2 VALUES (4, 'jack', 4)") 13 | 14 | var rows: seq[seq[string]] 15 | var cols: DbColumns 16 | 17 | for r in instantRows(db, cols, 18 | sql"""SELECT * FROM tst 19 | INTERSECT 20 | SELECT * FROM tst2 21 | ORDER BY c"""): 22 | rows.add(@[r[0], r[1], r[2]]) 23 | 24 | doAssert cols.len == 3 25 | doAssert cols[0].name == "A" 26 | doAssert cols[0].typ.kind == dbInt 27 | doAssert cols[1].name == "B" 28 | doAssert cols[1].typ.kind == dbVarchar 29 | doAssert cols[2].name == "C" 30 | doAssert cols[2].typ.kind == dbInt 31 | 32 | doAssert rows.len == 1 33 | doAssert rows[0][0] == "2" 34 | doAssert rows[0][1] == "king" 35 | doAssert rows[0][2] == "2" 36 | 37 | exec(db, sql"CREATE TABLE tst3 (a int, b text primary key)") 38 | exec(db, sql"INSERT INTO tst3 VALUES (2, 'king')") 39 | exec(db, sql"INSERT INTO tst3 VALUES (2, 'jack')") 40 | exec(db, sql"INSERT INTO tst3 VALUES (3, 'ace')") 41 | 42 | rows = getAllRows(db, sql"""SELECT a, b FROM tst 43 | INTERSECT 44 | SELECT * FROM tst3 45 | ORDER BY b DESC""") 46 | 47 | doAssert rows.len == 2 48 | doAssert rows[0][0] == "2" 49 | doAssert rows[0][1] == "king" 50 | doAssert rows[1][0] == "2" 51 | doAssert rows[1][1] == "jack" 52 | 53 | rows = getAllRows(db, sql"""SELECT * FROM tst3 54 | INTERSECT 55 | SELECT a, b FROM tst 56 | ORDER BY b DESC""") 57 | 58 | doAssert rows.len == 2 59 | doAssert rows[0][0] == "2" 60 | doAssert rows[0][1] == "king" 61 | doAssert rows[1][0] == "2" 62 | doAssert rows[1][1] == "jack" 63 | 64 | rows = getAllRows(db, sql"""SELECT c FROM tst2 65 | INTERSECT 66 | SELECT c * 2 FROM tst 67 | WHERE c = 2 68 | ORDER BY c""") 69 | 70 | doAssert rows.len == 1 71 | doAssert rows[0][0] == "4" 72 | 73 | rows = getAllRows(db, sql"""SELECT a FROM tst 74 | INTERSECT ALL 75 | SELECT 2 AS a FROM tst""") 76 | 77 | doAssert rows.len == 2 78 | doAssert rows[0][0] == "2" 79 | doAssert rows[0][0] == "2" 80 | 81 | close(db) 82 | -------------------------------------------------------------------------------- /tests/key.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | 5 | try: 6 | exec(db, sql"CREATE TABLE tst (a int primary key, a text, c text)") 7 | raiseAssert("CREATE TABLE succeeded with two columns having the same name") 8 | except DbError as e: 9 | doAssert e.sqlState() == "42601" 10 | 11 | exec(db, sql"CREATE TABLE tst (a int primary key, b text, c text)") 12 | 13 | exec(db, sql"INSERT INTO tst VALUES (1, 'x', 'y')") 14 | 15 | var rows = getAllRows(db, sql"SELECT * FROM tst WHERE a = 1") 16 | doAssert rows.len == 1 17 | doAssert rows[0][0] == "1" 18 | doAssert rows[0][1] == "x" 19 | doAssert rows[0][2] == "y" 20 | 21 | try: 22 | exec(db, sql"CREATE TABLE tst (a int, b text, c text, primary key(a, b))") 23 | raiseAssert("CREATE TABLE recreating existing table succeeded") 24 | except DbError as e: 25 | doAssert e.sqlState() == "42N01" 26 | 27 | try: 28 | exec(db, sql"INSERT INTO tst VALUES (1, 'x', 'z ')") 29 | raiseAssert("INSERT succeeded with same key") 30 | except DbError as e: 31 | doAssert e.sqlState() == "23505" 32 | 33 | exec(db, sql"CREATE TABLE tst2 (a int, b text, c text, primary key(b, a))") 34 | 35 | exec(db, sql"INSERT INTO tst2 VALUES (1, 'x', 'y')") 36 | 37 | rows = getAllRows(db, sql"SELECT * FROM tst2 WHERE a = 1 AND b = ?", "x") 38 | doAssert rows.len == 1 39 | doAssert rows[0][0] == "1" 40 | doAssert rows[0][1] == "x" 41 | doAssert rows[0][2] == "y" 42 | 43 | rows = getAllRows(db, sql"SELECT * FROM tst2 WHERE a = 1 AND b = 'x' AND c ='Y'") 44 | doAssert rows.len == 0 45 | 46 | rows = getAllRows(db, sql"SELECT * FROM tst2 WHERE a = 1") 47 | doAssert rows.len == 1 48 | doAssert rows[0][0] == "1" 49 | doAssert rows[0][1] == "x" 50 | doAssert rows[0][2] == "y" 51 | 52 | rows = getAllRows(db, sql"SELECT a, b FROM tst2 WHERE a = 1 AND b = 'x'") 53 | doAssert rows.len == 1 54 | doAssert rows[0].len == 2 55 | doAssert rows[0][0] == "1" 56 | doAssert rows[0][1] == "x" 57 | 58 | try: 59 | exec(db, sql"INSERT INTO tst2 VALUES (1, 'x', 'y')") 60 | raiseAssert("INSERT succeeded with same key") 61 | except DbError as e: 62 | doAssert e.sqlState() == "23505" 63 | -------------------------------------------------------------------------------- /tests/leftjoin.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"CREATE TABLE emp (empno int primary key, first_name text not null, last_name text)") 5 | exec(db, sql"CREATE TABLE emp_team (empno int, team_name text, primary key (empno, team_name))") 6 | exec(db, sql"CREATE TABLE emp2 (no int primary key, first_name text not null, last_name text, team_name text)") 7 | 8 | exec(db, sql"INSERT INTO emp VALUES(1, 'Bob', 'Base')") 9 | exec(db, sql"INSERT INTO emp VALUES(2, 'Daisy', 'Database')") 10 | exec(db, sql"INSERT INTO emp_team VALUES(1, 'Team A')") 11 | exec(db, sql"INSERT INTO emp_team VALUES(2, 'Team B')") 12 | exec(db, sql"INSERT INTO emp_team VALUES(3, 'Team C')") 13 | exec(db, sql"INSERT INTO emp2 VALUES(1, 'Bob', 'Base', 'Team A')") 14 | exec(db, sql"INSERT INTO emp2 VALUES(4, 'Dusty', 'Database', 'Team C')") 15 | 16 | var rows = getAllRows(db, sql"""SELECT * FROM emp_team t 17 | LEFT JOIN emp ON t.empno = emp.empno 18 | WHERE t.empno <= 2 19 | ORDER BY last_name""") 20 | doAssert rows.len == 2 21 | doAssert rows[0][0] == "1" 22 | doAssert rows[0][1] == "Team A" 23 | doAssert rows[0][2] == "1" 24 | doAssert rows[0][3] == "Bob" 25 | doAssert rows[0][4] == "Base" 26 | doAssert rows[1][0] == "2" 27 | doAssert rows[1][1] == "Team B" 28 | doAssert rows[1][2] == "2" 29 | doAssert rows[1][3] == "Daisy" 30 | doAssert rows[1][4] == "Database" 31 | 32 | rows = getAllRows(db, sql"""SELECT * FROM emp_team LEFT OUTER JOIN emp2 33 | ON no = empno 34 | ORDER BY emp_team.team_name""") 35 | doAssert rows.len == 3 36 | doAssert rows[0][0] == "1" 37 | doAssert rows[0][1] == "Team A" 38 | doAssert rows[0][2] == "1" 39 | doAssert rows[0][3] == "Bob" 40 | doAssert rows[0][4] == "Base" 41 | doAssert rows[1][0] == "2" 42 | doAssert rows[1][1] == "Team B" 43 | doAssert rows[1][2] == "" 44 | doAssert rows[1][3] == "" 45 | doAssert rows[1][4] == "" 46 | doAssert rows[2][0] == "3" 47 | doAssert rows[2][1] == "Team C" 48 | doAssert rows[2][2] == "" 49 | doAssert rows[2][3] == "" 50 | doAssert rows[2][4] == "" 51 | 52 | rows = getAllRows(db, sql"""SELECT * FROM emp_team LEFT JOIN emp2 53 | ON emp_team.team_name = emp2.team_name 54 | ORDER BY emp_team.team_name""") 55 | doAssert rows.len == 3 56 | doAssert rows[0][0] == "1" 57 | doAssert rows[0][1] == "Team A" 58 | doAssert rows[0][2] == "1" 59 | doAssert rows[0][3] == "Bob" 60 | doAssert rows[0][4] == "Base" 61 | doAssert rows[0][5] == "Team A" 62 | doAssert rows[1][0] == "2" 63 | doAssert rows[1][1] == "Team B" 64 | doAssert rows[1][2] == "" 65 | doAssert rows[1][3] == "" 66 | doAssert rows[1][4] == "" 67 | doAssert rows[1][5] == "" 68 | doAssert rows[2][0] == "3" 69 | doAssert rows[2][1] == "Team C" 70 | doAssert rows[2][2] == "4" 71 | doAssert rows[2][3] == "Dusty" 72 | doAssert rows[2][4] == "Database" 73 | doAssert rows[2][5] == "Team C" 74 | -------------------------------------------------------------------------------- /tests/like.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql/like 2 | 3 | doAssert matchesLike("", "") 4 | doAssert matchesLike("", "%") 5 | doAssert matchesLike("Grummel", "%") 6 | doAssert matchesLike("Grummel", "%_") 7 | doAssert matchesLike("Grummel", "%umme%") 8 | doAssert matchesLike("Grummel", "%ru%me%") 9 | doAssert matchesLike("Grummel", "Grum%mel") 10 | doAssert matchesLike("Grummel", "Grum%mel") 11 | doAssert matchesLike("Grummel", "Grum_el") 12 | doAssert matchesLike("Grummel", "Gr%l") 13 | doAssert matchesLike("Grummel", "Gr%m%l") 14 | doAssert matchesLike("Grummel", "Gru__el") 15 | doAssert matchesLike("Blabli", "%l_") 16 | doAssert matchesLike("Blabli", "%l%") 17 | doAssert matchesLike("Sql", "Sq_") 18 | doAssert matchesLike("Abrakadabra", "%ra_ad%") 19 | 20 | doAssert not matchesLike(" ", "") 21 | doAssert not matchesLike("", "_") 22 | doAssert not matchesLike("Grummel", "%umme") 23 | doAssert not matchesLike("Grummel", "umme%") 24 | doAssert not matchesLike("Grummel", "Gru_el") 25 | doAssert not matchesLike("Grummel", "Gr%ml") 26 | doAssert not matchesLike("Blabli", "%la_") 27 | doAssert not matchesLike("Abrakadabra", "%ra_ab%") 28 | -------------------------------------------------------------------------------- /tests/nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"../src/" 2 | -------------------------------------------------------------------------------- /tests/null.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"CREATE TABLE tst (a int primary key, b text, c text, d text NOT NULL)") 5 | exec(db, sql"INSERT INTO tst VALUES (1, NULL, 'yo', 'x')") 6 | exec(db, sql"INSERT INTO tst (a, b, d) VALUES (2, 'yoyo', 'y')") 7 | exec(db, sql"INSERT INTO tst (a, c, d) VALUES (3, NULL, 'z')") 8 | exec(db, sql"INSERT INTO tst VALUES (4, NULL, NULL, 'z')") 9 | 10 | try: 11 | exec(db, sql"INSERT INTO tst (a, c, d) VALUES (3, NULL, NULL)") 12 | raiseAssert("INSERT with non-nullable column set to NULL should fail") 13 | except DbError: 14 | discard 15 | 16 | var res: seq[seq[string]] 17 | 18 | for r in instantRows(db, sql"SELECT * FROM tst ORDER BY a"): 19 | res.add(@[r[0], r[1], r[2], r[3]]) 20 | doAssert res.len == 4 21 | doAssert res[0][0] == "1" 22 | doAssert res[0][1] == "" 23 | doAssert res[0][2] == "yo" 24 | doAssert res[0][3] == "x" 25 | doAssert res[1][0] == "2" 26 | doAssert res[1][1] == "yoyo" 27 | doAssert res[1][2] == "" 28 | doAssert res[1][3] == "y" 29 | doAssert res[2][0] == "3" 30 | doAssert res[2][1] == "" 31 | doAssert res[2][2] == "" 32 | doAssert res[2][3] == "z" 33 | doAssert res[3][0] == "4" 34 | doAssert res[3][1] == "" 35 | doAssert res[3][2] == "" 36 | doAssert res[3][3] == "z" 37 | 38 | var count = 0 39 | for r in instantRows(db, sql"SELECT * FROM tst WHERE a = NULL"): 40 | count += 1 41 | doAssert count == 0 42 | 43 | var rows = getAllRows(db, sql"SELECT b FROM tst WHERE a IN (?, ?) ORDER BY b", 1, 2) 44 | doAssert rows.len == 2 45 | doAssert rows[0][0] == "" 46 | doAssert rows[1][0] == "yoyo" 47 | 48 | exec(db, sql"UPDATE tst SET b = NULL WHERE a = 2") 49 | 50 | res = @[] 51 | for r in instantRows(db, sql"SELECT * FROM tst WHERE a = 2 AND b IS NULL"): 52 | res.add(@[r[0], r[1], r[2], r[3]]) 53 | doAssert res.len == 1 54 | doAssert res[0][0] == "2" 55 | doAssert res[0][1] == "" 56 | doAssert res[0][2] == "" 57 | doAssert res[0][3] == "y" 58 | 59 | res = @[] 60 | for r in instantRows(db, sql"SELECT * FROM tst WHERE c IS NOT NULL"): 61 | res.add(@[r[0], r[1], r[2], r[3]]) 62 | doAssert res.len == 1 63 | doAssert res[0][0] == "1" 64 | doAssert res[0][1] == "" 65 | doAssert res[0][2] == "yo" 66 | doAssert res[0][3] == "x" 67 | 68 | # Error 69 | try: 70 | exec(db, sql"UPDATE tst SET a = NULL WHERE a = 2") 71 | raiseAssert("UPDATE setting primary key to NULL should fail") 72 | except DbError: 73 | discard 74 | 75 | try: 76 | exec(db, sql"UPDATE tst SET d = NULL WHERE a = 2") 77 | raiseAssert("UPDATE setting non-null column to NULL should fail") 78 | except DbError: 79 | discard 80 | 81 | doAssert getValue(db, sql"SELECT TRUE OR b FROM tst WHERE a = 4") == "" 82 | -------------------------------------------------------------------------------- /tests/numeric.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | import strutils 4 | 5 | let db = open("", "", "", "") 6 | exec(db, sql"""CREATE TABLE tst 7 | (a int primary key, b numeric, c numeric(10), d numeric(18, 5), 8 | e real, f integer, g double precision, h bigint)""") 9 | 10 | doAssert execAffectedRows(db, sql"INSERT INTO tst VALUES (1, 2, 3.6, 1200.004, 130.12, 7, 1.7e6, 9223372036854775807)") == 1 11 | 12 | var res: seq[Row] 13 | 14 | for r in rows(db, sql"SELECT * FROM tst"): 15 | res.add(r) 16 | 17 | doAssert res.len == 1 18 | doAssert res[0][0] == "1" 19 | doAssert res[0][1] == "2" 20 | doAssert res[0][2] == "4" 21 | doAssert res[0][3] == "1200.00400" 22 | doAssert res[0][4] == "130.12" 23 | doAssert res[0][5] == "7" 24 | doAssert parseFloat(res[0][6]) == 1.7e6 25 | doAssert res[0][7] == "9223372036854775807" 26 | 27 | res = getAllRows(db, sql"SELECT t.d * 2, t.e * 2, t.d * 2.1, 1.1 * t.e, d + f, h - b FROM tst t") 28 | 29 | doAssert res.len == 1 30 | doAssert parseFloat(res[0][0]) == 2400.008 31 | doAssert res[0][1] == "260.24" 32 | doAssert parseFloat(res[0][2]) == 2520.0084 33 | doAssert res[0][3] == "143.132" 34 | doAssert parseFloat(res[0][4]) == 1207.004 35 | doAssert res[0][5] == "9223372036854775805" 36 | 37 | res = getAllRows(db, 38 | sql"""SELECT ? + ?, 5.5 + 200.25, 20 - ?, ? / ?, 39 | CASE 40 | WHEN tst.b > 1000 THEN 'Very high' 41 | WHEN tst.b > 100 THEN 'High' 42 | WHEN tst.b > 10 THEN 'Medium' 43 | WHEN tst.b > 1 THEN 'Low' 44 | ELSE 'Very low' 45 | END, 46 | CASE tst.f 47 | WHEN 6 THEN 'Six' 48 | WHEN 7 THEN 'Seven' 49 | WHEN 8 THEN 'Eight' 50 | ELSE 'Other' 51 | END, 52 | CASE tst.f 53 | WHEN 6 THEN 'Six' 54 | END 55 | FROM tst""", 56 | "3", "2", "1.1", "5", "2") 57 | 58 | doAssert res.len == 1 59 | doAssert res[0][0] == "5" 60 | doAssert res[0][1] == "205.75" 61 | doAssert res[0][2] == "18.9" 62 | doAssert res[0][3] == "2.5" 63 | doAssert res[0][4] == "Low" 64 | doAssert res[0][5] == "Seven" 65 | doAssert res[0][6] == "" 66 | 67 | try: 68 | exec(db, sql"UPDATE tst SET f = h") 69 | raiseAssert("updating integer column with large bigint succeeded") 70 | except DbError: 71 | discard 72 | 73 | exec(db, sql"UPDATE tst SET f = h / 100000000000000") 74 | 75 | exec(db, sql"CREATE TABLE tst2 (a decimal primary key, b decimal(10), c dec(18, 8))") 76 | 77 | doAssert execAffectedRows(db, sql"INSERT INTO tst2 VALUES (1, 12345678901, 1111111111.11111111)") == 1 78 | 79 | res = @[] 80 | var cols: DbColumns 81 | for r in instantRows(db, cols, sql"SELECT a, b, c, c + 1000000000.00000001, a + 1 a1 FROM tst2"): 82 | res.add(@[r[0], r[1], r[2], r[3]]) 83 | 84 | doAssert cols.len == 5 85 | doAssert cols[0].name == "A" 86 | doAssert cols[0].typ.kind == dbDecimal 87 | doAssert cols[1].name == "B" 88 | doAssert cols[1].typ.kind == dbDecimal 89 | doAssert cols[2].name == "C" 90 | doAssert cols[2].typ.kind == dbDecimal 91 | doAssert cols[3].name == "" 92 | doAssert cols[3].typ.kind == dbUnknown 93 | doAssert cols[4].name == "A1" 94 | doAssert cols[4].typ.kind == dbUnknown 95 | 96 | doAssert res[0][0] == "1" 97 | doAssert res[0][1] == "12345678901" 98 | doAssert res[0][2] == "1111111111.11111111" 99 | doAssert res[0][3] == "2111111111.11111112" 100 | 101 | exec(db, sql"UPDATE tst SET d = 12345.123455, f = 12345.5") 102 | 103 | var r = getRow(db, sql"SELECT d, f FROM tst") 104 | doAssert r[0] == "12345.12346" 105 | doAssert r[1] == "12346" 106 | 107 | doAssert getValue(db, sql"SELECT COUNT(*) FROM tst WHERE b <= ?", "2") == "1" 108 | 109 | try: 110 | exec(db, sql"UPDATE tst set d = 12345678901234.1234") 111 | raiseAssert("UPDATE succeded although value was too large") 112 | except DbError: 113 | discard 114 | 115 | close(db) 116 | -------------------------------------------------------------------------------- /tests/order.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"CREATE TABLE tst (a int PRIMARY KEY, b text, c text)") 5 | exec(db, sql"INSERT INTO tst VALUES (1, 'y', 'ace')") 6 | exec(db, sql"INSERT INTO tst VALUES (2, 'x', 'king')") 7 | exec(db, sql"INSERT INTO tst VALUES (3, 'y', 'queen')") 8 | exec(db, sql"INSERT INTO tst VALUES (4, 'x', 'jack')") 9 | 10 | var rows = getAllRows(db, sql"SELECT * FROM tst t ORDER BY b, t.a") 11 | doAssert rows.len == 4 12 | doAssert rows[0][0] == "2" 13 | doAssert rows[0][1] == "x" 14 | doAssert rows[0][2] == "king" 15 | doAssert rows[1][0] == "4" 16 | doAssert rows[1][1] == "x" 17 | doAssert rows[1][2] == "jack" 18 | doAssert rows[2][0] == "1" 19 | doAssert rows[2][1] == "y" 20 | doAssert rows[2][2] == "ace" 21 | doAssert rows[3][0] == "3" 22 | doAssert rows[3][1] == "y" 23 | doAssert rows[3][2] == "queen" 24 | 25 | rows = getAllRows(db, sql"SELECT a, b, c, a + 1 AS a1 FROM tst t ORDER BY a1 DESC") 26 | doAssert rows.len == 4 27 | doAssert rows[0][0] == "4" 28 | doAssert rows[0][1] == "x" 29 | doAssert rows[0][2] == "jack" 30 | doAssert rows[1][0] == "3" 31 | doAssert rows[1][1] == "y" 32 | doAssert rows[1][2] == "queen" 33 | doAssert rows[2][0] == "2" 34 | doAssert rows[2][1] == "x" 35 | doAssert rows[2][2] == "king" 36 | doAssert rows[3][0] == "1" 37 | doAssert rows[3][1] == "y" 38 | doAssert rows[3][2] == "ace" 39 | -------------------------------------------------------------------------------- /tests/prepared.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"CREATE TABLE tst (a int primary key, b char, c text)") 5 | 6 | exec(db, prepare(db, sql"INSERT INTO tst VALUES ($1, $2, $3)"), "1", "y", "Yoyoo") 7 | 8 | doAssert tryExec(db, prepare(db, sql"INSERT INTO tst VALUES ($1, $2, $3)"), 9 | "2", "c", "Xox") == true 10 | 11 | doAssert execAffectedRows(db, prepare(db, sql"INSERT INTO tst VALUES ($1, $2, $3)"), 12 | "3", "d", "bloo") == 1 13 | 14 | var res: seq[seq[string]] 15 | for r in instantRows(db, prepare(db, sql"SELECT * FROM tst WHERE a <= $1 ORDER BY a"), "2"): 16 | res.add(@[r[0], r[1], r[2]]) 17 | 18 | doAssert res.len == 2 19 | doAssert res[0][0] == "1" 20 | doAssert res[0][1] == "y" 21 | doAssert res[0][2] == "Yoyoo" 22 | doAssert res[1][0] == "2" 23 | doAssert res[1][1] == "c" 24 | doAssert res[1][2] == "Xox" 25 | 26 | res = @[] 27 | for r in rows(db, prepare(db, sql"SELECT * FROM tst WHERE a <= $1 ORDER BY a"), "2"): 28 | res.add(@[r[0], r[1], r[2]]) 29 | 30 | doAssert res.len == 2 31 | doAssert res[0][0] == "1" 32 | doAssert res[0][1] == "y" 33 | doAssert res[0][2] == "Yoyoo" 34 | doAssert res[1][0] == "2" 35 | doAssert res[1][1] == "c" 36 | doAssert res[1][2] == "Xox" 37 | 38 | res = getAllRows(db, prepare(db, sql"SELECT * FROM tst WHERE a >= $1 ORDER BY b"), "2") 39 | 40 | doAssert res.len == 2 41 | doAssert res[0][0] == "2" 42 | doAssert res[0][1] == "c" 43 | doAssert res[0][2] == "Xox" 44 | doAssert res[1][0] == "3" 45 | doAssert res[1][1] == "d" 46 | doAssert res[1][2] == "bloo" 47 | 48 | let row = getRow(db, prepare(db, sql"SELECT * FROM tst WHERE a = $1"), "1") 49 | doAssert row[0] == "1" 50 | doAssert row[1] == "y" 51 | doAssert row[2] == "Yoyoo" 52 | 53 | let val = getValue(db, prepare(db, sql"SELECT c FROM tst WHERE a = $1"), "1") 54 | doAssert val == "Yoyoo" 55 | -------------------------------------------------------------------------------- /tests/rollback.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"CREATE TABLE tst (a int primary key, b int, c text)") 5 | exec(db, sql"CREATE TABLE tst2 (a int primary key, s text)") 6 | 7 | exec(db, sql"INSERT INTO tst VALUES (1, 2, 'yo')") 8 | exec(db, sql"INSERT INTO tst VALUES (2, 3, 'ya')") 9 | 10 | db.setAutocommit(false) 11 | exec(db, sql"INSERT INTO tst VALUES (3, 3, 'yai')") 12 | 13 | exec(db, sql"UPDATE tst SET a = a + 10 WHERE b = 3") 14 | exec(db, sql"UPDATE tst SET c = 'yi' WHERE a = 1") 15 | 16 | exec(db, sql"DELETE FROM tst WHERE a = 12"); 17 | 18 | exec(db, sql"DROP TABLE tst2") 19 | 20 | exec(db, sql"CREATE TABLE tst3 (a int primary key, s text)") 21 | 22 | exec(db, sql"INSERT INTO tst3 VALUES (1, 'xoo')") 23 | 24 | exec(db, sql"ROLLBACK") 25 | 26 | var rows = getAllRows(db, sql"SELECT * FROM tst ORDER BY a") 27 | doAssert rows.len == 2 28 | doAssert rows[0][0] == "1" 29 | doAssert rows[0][1] == "2" 30 | doAssert rows[0][2] == "yo" 31 | doAssert rows[1][0] == "2" 32 | doAssert rows[1][1] == "3" 33 | doAssert rows[1][2] == "ya" 34 | 35 | # tst2 must exist again 36 | rows = getAllRows(db, sql"SELECT * FROM tst2") 37 | 38 | # tst3 must be have been dropped by the rollback 39 | try: 40 | rows = getAllRows(db, sql"SELECT * FROM tst3") 41 | raiseAssert("Accessing tst3 was succeeded") 42 | except DbError: 43 | # ok 44 | discard 45 | 46 | db.close() 47 | -------------------------------------------------------------------------------- /tests/snapshots.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | var db = open("", "", "", "") 4 | exec(db, sql"""CREATE TABLE tst( 5 | a int primary key, 6 | b numeric(10,5) DEFAULT 1.23, 7 | c integer, 8 | d text, 9 | e varchar(40), 10 | f real, 11 | g bigint, 12 | h time, 13 | k date)""") 14 | 15 | exec(db, sql"INSERT INTO tst VALUES (1, 3.6, 1200, 'Water', 'Fire', 7.8, 9223372036854775805, '17:05:06', '1901-05-02')") 16 | 17 | exec(db, sql"""CREATE TABLE tstdef( 18 | a int primary key, 19 | t time default '11:11:00', 20 | d date default '2007-06-05', 21 | ts timestamp default '2000-01-01 09:00:00.50000', 22 | ts3 timestamp(3) default '2020-02-01 14:00:00.123')""") 23 | 24 | save(db, "snapshot.dump") 25 | 26 | db = open("", "", "", "") 27 | restore(db, "snapshot.dump") 28 | 29 | exec(db, sql"INSERT INTO tst (a, c, d, e, f, g) VALUES (2, 2000, 'Wine', 'Earth', 1.5e5, 1000)") 30 | 31 | let rows = getAllRows(db, sql"SELECT * FROM tst ORDER BY a") 32 | 33 | doAssert rows.len == 2 34 | doAssert rows[0][0] == "1" 35 | doAssert rows[0][1] == "3.60000" 36 | doAssert rows[0][2] == "1200" 37 | doAssert rows[0][3] == "Water" 38 | doAssert rows[0][4] == "Fire" 39 | doAssert rows[0][5] == "7.8" 40 | doAssert rows[0][6] == "9223372036854775805" 41 | doAssert rows[0][7] == "17:05:06" 42 | doAssert rows[0][8] == "1901-05-02" 43 | doAssert rows[1][0] == "2" 44 | doAssert rows[1][1] == "1.23000" 45 | doAssert rows[1][2] == "2000" 46 | doAssert rows[1][3] == "Wine" 47 | doAssert rows[1][4] == "Earth" 48 | doAssert rows[1][5] == "150000.0" 49 | doAssert rows[1][6] == "1000" 50 | 51 | exec(db, sql"""INSERT INTO tstdef (a) values(1)""") 52 | 53 | let row = getRow(db, sql"""SELECT t, d, ts, ts3 FROM tstdef""") 54 | assert row[0] == "11:11:00" 55 | assert row[1] == "2007-06-05" 56 | assert row[2] == "2000-01-01 09:00:00.500000" 57 | assert row[3] == "2020-02-01 14:00:00.123" 58 | -------------------------------------------------------------------------------- /tests/subqueries.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import parseutils 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"CREATE TABLE s (sno integer primary key, sname text)") 6 | exec(db, sql"CREATE TABLE sp (sno integer, pno integer, primary key(sno, pno))") 7 | 8 | exec(db, sql"INSERT INTO s VALUES(1, 'one')") 9 | exec(db, sql"INSERT INTO s VALUES(2, 'two')") 10 | exec(db, sql"INSERT INTO s VALUES(3, 'three')") 11 | exec(db, sql"INSERT INTO s VALUES(4, 'four')") 12 | exec(db, sql"INSERT INTO sp VALUES(1, 1)") 13 | exec(db, sql"INSERT INTO sp VALUES(2, 2)") 14 | exec(db, sql"INSERT INTO sp VALUES(3, 1)") 15 | exec(db, sql"INSERT INTO sp VALUES(4, 3)") 16 | 17 | var res = getAllRows(db, sql"""SELECT s.sname FROM s 18 | WHERE EXISTS ( 19 | SELECT * FROM sp 20 | WHERE sp.pno = s.sno) 21 | ORDER BY s.sname""") 22 | doAssert res.len == 3 23 | doAssert res[0][0] == "one" 24 | doAssert res[1][0] == "three" 25 | doAssert res[2][0] == "two" 26 | 27 | res = getAllRows(db, sql"""SELECT DISTINCT s.sname FROM s 28 | WHERE 1 IN ( 29 | SELECT sp.pno FROM sp 30 | WHERE sp.sno = s.sno) 31 | ORDER BY s.sname DESC""") 32 | doAssert res.len == 2 33 | doAssert res[0][0] == "three" 34 | doAssert res[1][0] == "one" 35 | 36 | res = getAllRows(db, sql"""SELECT DISTINCT s.sname FROM s 37 | WHERE s.sno = ( 38 | SELECT sp.sno FROM sp 39 | WHERE sp.pno = 3) AND TRUE""") 40 | doAssert res.len == 1 41 | doAssert res[0][0] == "four" 42 | 43 | res = getAllRows(db, sql"""SELECT DISTINCT s.sname FROM s 44 | WHERE s.sno = ( 45 | SELECT sp.sno FROM sp 46 | WHERE sp.pno = 3) AND FALSE""") 47 | doAssert res.len == 0 48 | 49 | res = getAllRows(db, sql"""SELECT * FROM s 50 | WHERE sname = (SELECT MIN(sname) FROM s)""") 51 | doAssert res.len == 1 52 | doAssert res[0][0] == "4" 53 | doAssert res[0][1] == "four" 54 | 55 | res = getAllRows(db, sql"""SELECT * FROM s 56 | WHERE sname = (SELECT MAX(sname) FROM s)""") 57 | doAssert res.len == 1 58 | doAssert res[0][0] == "2" 59 | doAssert res[0][1] == "two" 60 | 61 | exec(db, sql"CREATE TABLE employees (name text primary key, department int, salary int)") 62 | exec(db, sql"INSERT INTO employees VALUES('Fred', 1, 2000)") 63 | exec(db, sql"INSERT INTO employees VALUES('John', 2, 1200)") 64 | exec(db, sql"INSERT INTO employees VALUES('Laura', 1, 2200)") 65 | 66 | res = getAllRows(db, 67 | sql"""SELECT 68 | name, 69 | (SELECT AVG(salary) 70 | FROM employees 71 | WHERE department = emp.department), 72 | (SELECT SUM(salary) 73 | FROM employees 74 | WHERE department = emp.department) 75 | FROM employees emp 76 | ORDER by name""") 77 | 78 | doAssert res.len == 3 79 | var num: int 80 | doAssert res[0][0] == "Fred" 81 | discard parseInt(res[0][1], num) 82 | doAssert num == 2100 83 | doAssert res[0][2] == "4200" 84 | doAssert res[1][0] == "John" 85 | discard parseInt(res[1][1], num) 86 | doAssert num == 1200 87 | doAssert res[1][2] == "1200" 88 | doAssert res[2][0] == "Laura" 89 | discard parseInt(res[2][1], num) 90 | doAssert num == 2100 91 | doAssert res[2][2] == "4200" 92 | -------------------------------------------------------------------------------- /tests/txlog.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import os 3 | 4 | removeDir("db") 5 | 6 | var db = open("db", "", "", "") 7 | exec(db, sql"""CREATE TABLE tst 8 | (a int primary key, b numeric(10,5) DEFAULT 1.23, c integer, d text, e varchar(40), 9 | f real)""") 10 | 11 | exec(db, sql"INSERT INTO tst VALUES (1, 3.6, 1200, 'Water', 'Fire', 7.8)") 12 | 13 | exec(db, sql"INSERT INTO tst VALUES (2, 7.6, 200, 'Earth', 'Fire', 7.7)") 14 | 15 | exec(db, sql"DELETE FROM tst WHERE a = 2") 16 | 17 | close(db) 18 | 19 | db = open("db", "", "", "") 20 | 21 | exec(db, sql"INSERT INTO tst (a, c, d, e, f) VALUES (2, 2000, 'Wine', 'Earth', 1.5e5)") 22 | 23 | let rows = getAllRows(db, sql"SELECT * FROM tst ORDER BY a") 24 | 25 | doAssert rows.len == 2 26 | doAssert rows[0][0] == "1" 27 | doAssert rows[0][1] == "3.60000" 28 | doAssert rows[0][2] == "1200" 29 | doAssert rows[0][3] == "Water" 30 | doAssert rows[0][4] == "Fire" 31 | doAssert rows[0][5] == "7.8" 32 | doAssert rows[1][0] == "2" 33 | doAssert rows[1][1] == "1.23000" 34 | doAssert rows[1][2] == "2000" 35 | doAssert rows[1][3] == "Wine" 36 | doAssert rows[1][4] == "Earth" 37 | doAssert rows[1][5] == "150000.0" 38 | -------------------------------------------------------------------------------- /tests/txlog_snapshot.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import os 3 | 4 | removeDir("db") 5 | 6 | var db = open("db", "", "", "") 7 | exec(db, sql"""CREATE TABLE tst 8 | (a int primary key, b numeric(10,5) DEFAULT 1.23, c integer, d text, e varchar(40), 9 | f real)""") 10 | 11 | exec(db, sql"INSERT INTO tst VALUES (1, 3.6, 1200, 'Water', 'Fire', 7.8)") 12 | 13 | exec(db, sql"INSERT INTO tst VALUES (2, 7.6, 200, 'Earth', 'Fire', 7.7)") 14 | 15 | exec(db, sql"DELETE FROM tst WHERE a = 2") 16 | 17 | exec(db, sql"""CREATE TABLE ttst 18 | (t time primary key, d date, ts timestamp, t3 time(3), ts2 timestamp(2))""") 19 | 20 | exec(db, sql"""INSERT INTO ttst VALUES ('20:05:10', '1950-05-11', '2002-03-05 15:16:17.654321', 21 | time '23:10:11.234', 22 | timestamp '1901-01-02 03:04:05.56')""") 23 | 24 | save(db) 25 | 26 | exec(db, sql"INSERT INTO tst (a, c, d, e, f) VALUES (3, 2000, 'Wine', 'Earth', 1.5e5)") 27 | 28 | close(db) 29 | 30 | db = open("db", "", "", "") 31 | 32 | var rows = getAllRows(db, sql"SELECT * FROM tst ORDER BY a") 33 | 34 | doAssert rows.len == 2 35 | doAssert rows[0][0] == "1" 36 | doAssert rows[0][1] == "3.60000" 37 | doAssert rows[0][2] == "1200" 38 | doAssert rows[0][3] == "Water" 39 | doAssert rows[0][4] == "Fire" 40 | doAssert rows[0][5] == "7.8" 41 | doAssert rows[1][0] == "3" 42 | doAssert rows[1][1] == "1.23000" 43 | doAssert rows[1][2] == "2000" 44 | doAssert rows[1][3] == "Wine" 45 | doAssert rows[1][4] == "Earth" 46 | doAssert rows[1][5] == "150000.0" 47 | 48 | rows = getAllRows(db, sql"SELECT * FROM ttst") 49 | 50 | doAssert rows.len == 1 51 | doAssert rows[0][0] == "20:05:10" 52 | doAssert rows[0][1] == "1950-05-11" 53 | doAssert rows[0][2] == "2002-03-05 15:16:17.654321" 54 | doAssert rows[0][3] == "23:10:11.234" 55 | doAssert rows[0][4] == "1901-01-02 03:04:05.56" 56 | 57 | close(db) 58 | -------------------------------------------------------------------------------- /tests/union.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"CREATE TABLE tst (a int primary key, b text)") 6 | exec(db, sql"CREATE TABLE tst2 (a int primary key, b text)") 7 | exec(db, sql"INSERT INTO tst VALUES (1, 'ace')") 8 | exec(db, sql"INSERT INTO tst VALUES (2, 'king')") 9 | exec(db, sql"INSERT INTO tst2 VALUES (2, 'king')") 10 | exec(db, sql"INSERT INTO tst2 VALUES (3, 'queen')") 11 | exec(db, sql"INSERT INTO tst2 VALUES (4, 'jack')") 12 | 13 | var rows: seq[seq[string]] 14 | var cols: DbColumns 15 | for r in instantRows(db, cols, 16 | sql"""SELECT * FROM tst 17 | UNION 18 | SELECT * FROM tst2 19 | ORDER BY a"""): 20 | rows.add(@[r[0], r[1]]) 21 | 22 | doAssert cols.len == 2 23 | doAssert cols[0].name == "A" 24 | doAssert cols[0].typ.kind == dbInt 25 | doAssert cols[1].name == "B" 26 | doAssert cols[1].typ.kind == dbVarchar 27 | 28 | doAssert rows.len == 4 29 | doAssert rows[0][0] == "1" 30 | doAssert rows[0][1] == "ace" 31 | doAssert rows[1][0] == "2" 32 | doAssert rows[1][1] == "king" 33 | doAssert rows[2][0] == "3" 34 | doAssert rows[2][1] == "queen" 35 | doAssert rows[3][0] == "4" 36 | doAssert rows[3][1] == "jack" 37 | 38 | rows = getAllRows(db, 39 | sql"""SELECT * FROM tst 40 | UNION ALL 41 | SELECT * FROM tst2 42 | ORDER BY a""") 43 | doAssert rows.len == 5 44 | doAssert rows[0][0] == "1" 45 | doAssert rows[0][1] == "ace" 46 | doAssert rows[1][0] == "2" 47 | doAssert rows[1][1] == "king" 48 | doAssert rows[2][0] == "2" 49 | doAssert rows[2][1] == "king" 50 | doAssert rows[3][0] == "3" 51 | doAssert rows[3][1] == "queen" 52 | doAssert rows[4][0] == "4" 53 | doAssert rows[4][1] == "jack" 54 | 55 | exec(db, sql"CREATE TABLE tst3 (a int primary key, n int)") 56 | exec(db, sql"INSERT INTO tst3 VALUES (3, 11)") 57 | 58 | rows = @[] 59 | for r in instantRows(db, cols, 60 | sql"""SELECT a, b FROM tst 61 | UNION 62 | SELECT a, CAST(n AS text) FROM tst3 63 | ORDER BY a"""): 64 | rows.add(@[r[0], r[1]]) 65 | doAssert cols.len == 2 66 | doAssert cols[0].name == "A" 67 | doAssert cols[0].typ.kind == dbInt 68 | doAssert cols[1].typ.kind == dbVarchar 69 | 70 | doAssert rows.len == 3 71 | doAssert rows[0][0] == "1" 72 | doAssert rows[0][1] == "ace" 73 | doAssert rows[1][0] == "2" 74 | doAssert rows[1][1] == "king" 75 | doAssert rows[2][0] == "3" 76 | doAssert rows[2][1] == "11" 77 | -------------------------------------------------------------------------------- /tests/update.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | 3 | let db = open("", "", "", "") 4 | exec(db, sql"CREATE TABLE tst (a int primary key, b int, c text)") 5 | exec(db, sql"INSERT INTO tst VALUES (1, 2, 'yo')") 6 | exec(db, sql"INSERT INTO tst VALUES (2, 3, 'ya')") 7 | 8 | exec(db, sql"UPDATE tst SET c = 'yoyo')") 9 | 10 | var rows = getAllRows(db, sql"SELECT * FROM tst ORDER BY b") 11 | doAssert rows.len == 2 12 | doAssert rows[0][0] == "1" 13 | doAssert rows[0][1] == "2" 14 | doAssert rows[0][2] == "yoyo" 15 | doAssert rows[1][0] == "2" 16 | doAssert rows[1][1] == "3" 17 | doAssert rows[1][2] == "yoyo" 18 | 19 | exec(db, sql"UPDATE tst SET b = b + 10 WHERE a = 1)") 20 | 21 | rows = getAllRows(db, sql"SELECT * FROM tst ORDER BY a") 22 | doAssert rows.len == 2 23 | doAssert rows[0][0] == "1" 24 | doAssert rows[0][1] == "12" 25 | doAssert rows[0][2] == "yoyo" 26 | doAssert rows[1][0] == "2" 27 | doAssert rows[1][1] == "3" 28 | doAssert rows[1][2] == "yoyo" 29 | 30 | exec(db, sql"UPDATE tst SET a = a + 10, c = 'x' WHERE a = 1)") 31 | 32 | rows = getAllRows(db, sql"SELECT * FROM tst ORDER BY a DESC") 33 | doAssert rows.len == 2 34 | doAssert rows[0][0] == "11" 35 | doAssert rows[0][1] == "12" 36 | doAssert rows[0][2] == "x" 37 | doAssert rows[1][0] == "2" 38 | doAssert rows[1][1] == "3" 39 | doAssert rows[1][2] == "yoyo" 40 | 41 | exec(db, sql"UPDATE tst SET a = a + 10, c = c || 'y')") 42 | 43 | rows = getAllRows(db, sql"SELECT * FROM tst ORDER BY a DESC") 44 | doAssert rows.len == 2 45 | doAssert rows[0][0] == "21" 46 | doAssert rows[0][1] == "12" 47 | doAssert rows[0][2] == "xy" 48 | doAssert rows[1][0] == "12" 49 | doAssert rows[1][1] == "3" 50 | doAssert rows[1][2] == "yoyoy" 51 | -------------------------------------------------------------------------------- /tests/where.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | import algorithm 4 | import strutils 5 | 6 | let db = open("", "", "", "") 7 | exec(db, sql"CREATE TABLE babababa (a text not null, b text, c int primary key, d bigint)") 8 | doAssert execAffectedRows(db, 9 | sql"""INSERT INTO babababa (a, b, c) 10 | VALUES('Baba', 'Ba' || lower('Baa') || upper('Baa'), 1)""" 11 | ) == 1 12 | exec(db, 13 | sql"""INSERT INTO babababa (a, b, c) VALUES('Electrica', 'Salsa', (1 + 2) * -3)""") 14 | exec(db, 15 | sql"""INSERT INTO babababa (a, b, c) VALUES('Alpen', NULL, 2)""") 16 | exec(db, 17 | sql"""INSERT INTO babababa (a, b, c, d) VALUES(?, ?, ?, ?)""", "Adam", "Eve", "3", "-9223372036854775808") 18 | 19 | var rows = getAllRows(db, sql"SELECT * FROM babababa b WHERE b.a = 'Baba' or c > 1") 20 | sort(rows) do (row1, row2: Row) -> int: 21 | parseInt(row1[2]) - parseInt(row2[2]) 22 | doAssert rows.len == 3 23 | doAssert rows[0][0] == "Baba" 24 | doAssert rows[0][1] == "BabaaBAA" 25 | doAssert rows[0][2] == "1" 26 | doAssert rows[1][0] == "Alpen" 27 | doAssert rows[1][1] == "" 28 | doAssert rows[1][2] == "2" 29 | doAssert rows[2][0] == "Adam" 30 | doAssert rows[2][1] == "Eve" 31 | doAssert rows[2][2] == "3" 32 | 33 | rows = getAllRows(db, sql"SELECT a FROM babababa WHERE b <> 'Eve' AND c >= 1") 34 | doAssert rows.len == 1 35 | doAssert rows[0][0] == "Baba" 36 | 37 | rows = @[] 38 | var cols: DbColumns 39 | for r in instantRows(db, cols, sql"SELECT * FROM babababa WHERE c IN (1,-9) ORDER BY c"): 40 | rows.add(@[r[0], r[1], r[2]]) 41 | 42 | doAssert cols.len == 4 43 | doAssert cols[0].name == "A" 44 | doAssert cols[0].typ.kind == dbVarchar 45 | doAssert cols[1].name == "B" 46 | doAssert cols[1].typ.kind == dbVarchar 47 | doAssert cols[2].name == "C" 48 | doAssert cols[2].typ.kind == dbInt 49 | doAssert cols[2].typ.size == 4 50 | doAssert cols[3].name == "D" 51 | doAssert cols[3].typ.kind == dbInt 52 | doAssert cols[3].typ.size == 8 53 | 54 | doAssert rows.len == 2 55 | doAssert rows[0][0] == "Electrica" 56 | doAssert rows[0][1] == "Salsa" 57 | doAssert rows[0][2] == "-9" 58 | doAssert rows[1][0] == "Baba" 59 | doAssert rows[1][1] == "BabaaBAA" 60 | doAssert rows[1][2] == "1" 61 | 62 | rows = getAllRows(db, sql"""SELECT * FROM babababa 63 | WHERE a NOT IN ('Adam', 'Baba') 64 | ORDER BY a""") 65 | doAssert rows.len == 2 66 | doAssert rows[0][0] == "Alpen" 67 | doAssert rows[0][1] == "" 68 | doAssert rows[0][2] == "2" 69 | doAssert rows[1][0] == "Electrica" 70 | doAssert rows[1][1] == "Salsa" 71 | doAssert rows[1][2] == "-9" 72 | 73 | rows = getAllRows(db, sql"SELECT * FROM babababa WHERE a LIKE ?", "%lpe%") 74 | doAssert rows.len == 1 75 | doAssert rows[0][0] == "Alpen" 76 | doAssert rows[0][1] == "" 77 | doAssert rows[0][2] == "2" 78 | 79 | rows = getAllRows(db, sql"SELECT * FROM babababa WHERE d < ?", "-9223372036854775000") 80 | doAssert rows.len == 1 81 | doAssert rows[0][0] == "Adam" 82 | doAssert rows[0][1] == "Eve" 83 | doAssert rows[0][2] == "3" 84 | doAssert rows[0][3] == "-9223372036854775808" 85 | 86 | rows = getAllRows(db, sql"SELECT * FROM babababa WHERE d = ?", "-9223372036854775808") 87 | doAssert rows.len == 1 88 | doAssert rows[0][0] == "Adam" 89 | doAssert rows[0][1] == "Eve" 90 | doAssert rows[0][2] == "3" 91 | doAssert rows[0][3] == "-9223372036854775808" 92 | -------------------------------------------------------------------------------- /tests/with.nim: -------------------------------------------------------------------------------- 1 | import db_nimternalsql 2 | import db_common 3 | 4 | let db = open("", "", "", "") 5 | exec(db, sql"CREATE TABLE tst (a int primary key, b text)") 6 | 7 | exec(db, sql"INSERT INTO tst VALUES (1, 'Abcdef')") 8 | exec(db, sql"INSERT INTO tst VALUES (2, 'Bcdefg')") 9 | 10 | var rows = getAllRows(db, 11 | sql"""WITH t1 AS ( 12 | SELECT a, b FROM tst WHERE a = 2 13 | ) 14 | SELECT b FROM t1""") 15 | 16 | doAssert rows.len == 1 17 | doAssert rows[0][0] == "Bcdefg" 18 | 19 | exec(db, sql"CREATE TABLE d (t text primary key)") 20 | exec(db, sql"INSERT INTO d VALUES ('')") 21 | 22 | exec(db, sql"INSERT INTO tst VALUES (3, '123.111')") 23 | 24 | rows = getAllRows(db, 25 | sql"""WITH t1 AS ( 26 | SELECT a, b FROM tst WHERE a = 3 27 | ) 28 | SELECT 29 | CAST((SELECT b FROM t1) AS NUMERIC(5, 2)), 30 | TRIM(CAST((SELECT b FROM t1) AS TEXT)), 31 | CASE 32 | WHEN (SELECT b FROM t1) = 123.111 THEN 'yes' 33 | ELSE 'no' 34 | END 35 | FROM d""") 36 | 37 | doAssert rows.len == 1 38 | doAssert rows[0][0] == "123.11" 39 | doAssert rows[0][1] == "123.111" 40 | doAssert rows[0][2] == "yes" 41 | 42 | exec(db, sql"CREATE TABLE tst2 (a int primary key, b text)") 43 | exec(db, sql"INSERT INTO tst2 VALUES (1, 'w')") 44 | exec(db, sql"INSERT INTO tst2 VALUES (2, 'x')") 45 | exec(db, sql"INSERT INTO tst2 VALUES (3, 'y')") 46 | 47 | rows = getAllRows(db, 48 | sql"""WITH t2 AS ( 49 | SELECT * FROM tst2 WHERE a = 2 50 | ) 51 | SELECT b FROM tst WHERE a IN (SELECT a FROM t2)""") 52 | 53 | doAssert rows.len == 1 54 | doAssert rows[0][0] == "Bcdefg" 55 | 56 | rows = getAllRows(db, 57 | sql"""WITH t2 AS ( 58 | SELECT * FROM tst2 WHERE a = 2 59 | ) 60 | SELECT b FROM tst WHERE EXISTS (SELECT a FROM t2 WHERE t2.a = tst.a)""") 61 | 62 | doAssert rows.len == 1 63 | doAssert rows[0][0] == "Bcdefg" 64 | 65 | rows = getAllRows(db, 66 | sql"""WITH t2 AS ( 67 | SELECT a, b FROM tst2 WHERE a = 2 68 | ) 69 | SELECT b FROM tst WHERE EXISTS (SELECT a FROM t2 WHERE t2.a = tst.a)""") 70 | 71 | doAssert rows.len == 1 72 | doAssert rows[0][0] == "Bcdefg" 73 | 74 | exec(db, sql"CREATE TABLE orders (order_id int primary key, region text, quantity int, amount int, product text)") 75 | 76 | exec(db, sql"INSERT INTO orders VALUES(1, 'USA', 7, 50, 'Coffee')") 77 | exec(db, sql"INSERT INTO orders VALUES(2, 'France', 17, 80, 'Coffee')") 78 | exec(db, sql"INSERT INTO orders VALUES(3, 'Italy', 1, 4, 'Tea')") 79 | exec(db, sql"INSERT INTO orders VALUES(4, 'Italy', 5, 10, 'Coffee')") 80 | exec(db, sql"INSERT INTO orders VALUES(5, 'France', 10, 20, 'Tea')") 81 | exec(db, sql"INSERT INTO orders VALUES(6, 'France', 2, 10, 'Coffee')") 82 | 83 | rows = getAllRows(db, 84 | sql"""WITH regional_sales AS ( 85 | SELECT region, SUM(amount) AS total_sales 86 | FROM orders 87 | GROUP BY region 88 | ), top_regions AS ( 89 | SELECT region 90 | FROM regional_sales 91 | WHERE total_sales * 10 > (SELECT SUM(total_sales) FROM regional_sales) 92 | ) 93 | SELECT region, 94 | product, 95 | SUM(quantity) AS product_units, 96 | SUM(amount) AS product_sales 97 | FROM orders 98 | WHERE region IN (SELECT region FROM top_regions) 99 | GROUP BY region, product 100 | ORDER BY region, product""") 101 | 102 | doAssert rows.len == 3 103 | doAssert rows[0][0] == "France" 104 | doAssert rows[0][1] == "Coffee" 105 | doAssert rows[0][2] == "19" 106 | doAssert rows[0][3] == "90" 107 | doAssert rows[1][0] == "France" 108 | doAssert rows[1][1] == "Tea" 109 | doAssert rows[1][2] == "10" 110 | doAssert rows[1][3] == "20" 111 | doAssert rows[2][0] == "USA" 112 | doAssert rows[2][1] == "Coffee" 113 | doAssert rows[2][2] == "7" 114 | doAssert rows[2][3] == "50" 115 | 116 | exec(db, sql"CREATE TABLE employees (name text primary key, department_id int)") 117 | exec(db, sql"CREATE TABLE departments (department_id int primary key, name text)") 118 | 119 | exec(db, sql"INSERT INTO departments VALUES (1, 'Sales')") 120 | exec(db, sql"INSERT INTO departments VALUES (2, 'Production')") 121 | 122 | exec(db, sql"INSERT INTO employees VALUES ('Fred', 1)") 123 | exec(db, sql"INSERT INTO employees VALUES ('Daisy', 1)") 124 | exec(db, sql"INSERT INTO employees VALUES ('John', 2)") 125 | exec(db, sql"INSERT INTO employees VALUES ('Eve', 1)") 126 | 127 | rows = getAllRows(db, 128 | sql"""WITH grp AS ( 129 | SELECT dept.name AS dept_name, COUNT(*) AS emp_count 130 | FROM employees AS emp 131 | JOIN departments AS dept ON emp.department_id = dept.department_id 132 | GROUP BY dept_name) 133 | SELECT * FROM grp 134 | WHERE grp.emp_count > 1""") 135 | 136 | doAssert rows.len == 1 137 | 138 | doAssert rows[0][0] == "Sales" 139 | doAssert rows[0][1] == "3" 140 | 141 | close(db) 142 | --------------------------------------------------------------------------------