You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/apis/DataAPI/DataBase.md
+333-3Lines changed: 333 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -94,12 +94,342 @@ For a database object `db`, with the following functions:
94
94
95
95
After the database is closed, do not continue to use it!
96
96
97
+
------
97
98
99
+
## 📋 SQL Database
98
100
99
-
------
101
+
SQL databases are suitable for handling large amounts of relational data using SQL statements. The underlying interface is implemented using a cross-database framework, supporting most common SQL databases on the market.
102
+
103
+
**Note:** Unless otherwise specified, the following APIs may throw exceptions. It is recommended to use exception handling blocks. For **JavaScript**, use `try ... catch` blocks; for **Lua**, use `pcall`. Generally, if no error is thrown, the call is successful.
104
+
105
+
> If you are a JavaScript plugin developer, you can also try using the [Yoyo](https://www.google.com/search?q=https://gitee.com/Y_oyo) LLDB Chained Operation Library (primarily for beginners who are unfamiliar with SQL syntax). Details: [Click here](https://gitee.com/Y_oyo/yoyo-mcbe-lite-xloader-item/blob/master/sql/yoyoSqlite.js%202.0.0.md)
106
+
107
+
### Open a SQL Database Session
108
+
109
+
To achieve cross-database compatibility, connecting to a database requires passing an object containing connection parameters or a connection string.
110
+
111
+
**[JavaScript]**`new DBSession(type, params)`
112
+
113
+
**[Lua]**`DBSession(type, params)`
114
+
115
+
***Parameters:**
116
+
*`type`: `String`
117
+
The database type, supports `"sqlite3"` and `"mysql"`.
Connection string in formats like `file:///mydb.db?k=v` or `mysql://root:password@localhost:3306/db`.
135
+
136
+
137
+
***Returns:** The opened database session object.
138
+
***Return Type:**`DBSession`
139
+
* Returns `Null` if the connection fails.
140
+
141
+
142
+
143
+
#### Connection Parameters
144
+
145
+
| Key | Purpose | Supported DB | Example | Default |
146
+
| --- | --- | --- | --- | --- |
147
+
|`path`| Path to the database file |`SQLite`|`plugins/test.db`| - |
148
+
|`create`| Auto-create if file doesn't exist |`SQLite`|`true`/`false`|`true`|
149
+
|`readonly`| Open in read-only mode |`SQLite`|`true`/`false`|`false`|
150
+
|`readwrite`| Open in read-write mode |`SQLite`|`true`/`false`|`true`|
151
+
152
+
---
153
+
154
+
### Execute SQL and Get Result Set
155
+
156
+
`session.query(sql)`
157
+
158
+
***Parameters:**
159
+
*`sql`: `String`
160
+
The SQL statement to query.
161
+
162
+
163
+
***Returns:** Query results (result set).
164
+
***Return Type:**`Array<Array>`
165
+
The first row (`result[0]`) contains the table headers (column names); subsequent rows contain the data.
166
+
167
+
**Example Result:**
168
+
If the query returns:
169
+
| a | b |
170
+
| :--- | :--- |
171
+
| ll | 233 |
172
+
| h | 114 |
173
+
174
+
The `query` method returns:
175
+
176
+
```json
177
+
[
178
+
["a", "b"],
179
+
["ll", 233],
180
+
["h", 114]
181
+
]
182
+
183
+
```
184
+
185
+
---
186
+
187
+
### Execute SQL Without Returning Results
188
+
189
+
`session.exec(sql)`
190
+
191
+
`session.execute(sql)`
192
+
193
+
***Parameters:**
194
+
*`sql`: `String`
195
+
The SQL statement to execute.
196
+
197
+
198
+
***Returns:** The processed session object (for chaining).
199
+
***Return Type:**`DBSession`
200
+
201
+
---
202
+
203
+
### Check Session Status
204
+
205
+
`session.isOpen()`
206
+
207
+
***Returns:** Whether the session is currently open.
208
+
***Return Type:**`Boolean`
209
+
210
+
---
211
+
212
+
### Close Database Session
213
+
214
+
`session.close()`
215
+
216
+
***Returns:** Whether the close operation was successful.
217
+
***Return Type:**`Boolean`
218
+
219
+
---
220
+
221
+
### SQL Prepared Statements
222
+
223
+
> **Prepared Statements** are a crucial part of SQL. They work by sending a SQL statement with placeholders to the server to be compiled first, then binding parameters to it before execution. Different SQL engines may have different syntax for placeholders; please refer to the official documentation for the specific database you are using.
224
+
> The main purpose of prepared statements is to prevent **SQL Injection**—a common and dangerous attack. Directly using unvalidated user input (like BDS does xD) can lead to password bypass or data loss (e.g., executing `DROP TABLE`). It is highly recommended to use prepared statements for user input. Additionally, they improve performance by compiling the statement once for multiple executions with different values.
225
+
226
+
#### Prepare a Statement
227
+
228
+
`session.prepare(sql)`
229
+
230
+
***Parameters:**
231
+
*`sql`: `String`
232
+
The SQL statement to prepare.
233
+
234
+
235
+
***Returns:** A prepared statement object; throws an error on failure.
236
+
***Return Type:**`DBStmt`
237
+
238
+
##### Placeholder Syntax Examples
239
+
240
+
**SQLite:**
241
+
242
+
```sql
243
+
-- Single '?' for positional parameters
244
+
SELECT*FROM table WHERE id = ?;
245
+
-- '?X' and '?Y' (where X/Y are names) for named binding
246
+
INSERT INTO table VALUES (?X, ?Y);
247
+
-- '$X', ':Z', and '@V' are also supported named parameters
248
+
INSERT INTO table VALUES ($X, ?Y, :Z, @V);
249
+
250
+
```
251
+
252
+
**MySQL:**
253
+
254
+
```sql
255
+
-- Single '?' for positional parameters
256
+
SELECT*FROM table WHERE id = ?;
257
+
-- Native MySQL does not support named parameters; LLDB implements simple parsing for compatibility, but use with caution.
258
+
INSERT INTO table VALUES (?X, ?Y);
259
+
INSERT INTO table VALUES ($X, ?Y, :Z);
260
+
261
+
```
262
+
263
+
#### Prepared Statement - Properties
264
+
265
+
| Property | Description | Type | See Also |
266
+
| --- | --- | --- | --- |
267
+
|`stmt.affectedRows`| Rows affected by the last execution (INSERT, UPDATE, DELETE, etc.) |`Integer`|[SQLite](https://www.sqlite.org/c3ref/changes.html) / [MySQL](https://dev.mysql.com/doc/c-api/8.0/en/mysql-affected-rows.html)|
268
+
|`stmt.insertId`| The last inserted row ID (see official docs for row ID behavior) |`Integer`|[SQLite](https://www.sqlite.org/c3ref/last_insert_rowid.html) / [MySQL](https://dev.mysql.com/doc/c-api/8.0/en/mysql-stmt-insert-id.html)|
269
+
270
+
*These properties are read-only and only available after the statement is executed.*
271
+
272
+
---
273
+
274
+
#### Bind Parameters to a Statement
275
+
276
+
`stmt.bind(val)`
277
+
278
+
Binds the value to the first unbound parameter.
279
+
280
+
`stmt.bind(obj)`
281
+
282
+
Binds an object; equivalent to iterating through the object and calling `bind(val, key)`.
283
+
284
+
`stmt.bind(arr)`
285
+
286
+
Binds an array; equivalent to iterating through the array and calling `bind(val)`.
287
+
288
+
`stmt.bind(val, index)`
289
+
290
+
Binds the value to a specific index (starting from `0`).
291
+
292
+
`stmt.bind(val, name)`
293
+
294
+
Binds the value to a named parameter.
295
+
296
+
***Returns:** The statement object (for chaining).
297
+
***Return Type:**`DBStmt`
298
+
299
+
*After binding, you must call `stmt.execute()` to run the query.*
300
+
301
+
##### Binding Example:
302
+
303
+
```js
304
+
let stmt =session.prepare("INSERT INTO table VALUES ($a, $b, $c, $d, $e, $f, $g, $h)");
305
+
let values = {
306
+
c:"have you",
307
+
d:"finished",
308
+
e:"your",
309
+
f:"homework?"
310
+
};
311
+
stmt.bind(values); // Binds c, d, e, f
312
+
stmt.bind("LLSE"); // Binds to a
313
+
stmt.bind(["****", "mojang"]); // Binds to b and g
314
+
stmt.bind(114514, 7); // Binds to h (index 7)
315
+
316
+
```
317
+
318
+
---
319
+
320
+
#### Execute the Current Statement
321
+
322
+
`stmt.execute()`
323
+
324
+
***Returns:** The statement object (for chaining).
325
+
***Return Type:**`DBStmt`
326
+
327
+
#### Step to Next Result Row
328
+
329
+
`stmt.step()` or `stmt.next()`
330
+
331
+
***Returns:** Whether the step was successful (true if a row exists).
332
+
***Return Type:**`Boolean`
333
+
***Note:** The cursor is positioned at the **first row** immediately after execution. Use a `do...while` loop to iterate, otherwise the first row will be skipped.
334
+
335
+
#### Fetch Current Row
336
+
337
+
`stmt.fetch()`
338
+
339
+
***Returns:** The current result row as an object, e.g., `{col1: "value", col2: 2333}`.
340
+
***Return Type:**`Object`
341
+
342
+
#### Fetch All Result Rows
343
+
344
+
`stmt.fetchAll()`
345
+
346
+
***Returns:** The full result set. (See [Execute SQL and Get Result Set](https://www.google.com/search?q=%23execute-sql-and-get-result-set)).
347
+
***Return Type:**`Array<Array>`
348
+
349
+
`stmt.fetchAll(callback)`
350
+
351
+
***Parameters:**
352
+
*`callback`: `Function<bool(Object)>`
353
+
Function to iterate through rows. Returning `false` inside the callback stops the iteration.
354
+
355
+
356
+
***Returns:** The statement object.
357
+
***Return Type:**`DBStmt`
358
+
359
+
---
360
+
361
+
#### Reset Statement State
362
+
363
+
`stmt.reset()`
364
+
365
+
***Returns:** The statement object.
366
+
***Note:** This resets the statement to a "pending" state but **does not** clear bound parameters.
367
+
368
+
#### Re-execute Statement
369
+
370
+
`stmt.reexec()`
371
+
372
+
***Note:** A convenience function equivalent to calling `stmt.reset()` and then `stmt.execute()`.
373
+
374
+
#### Clear Bound Parameters
375
+
376
+
`stmt.clear()`
377
+
378
+
***Returns:** The statement object.
379
+
380
+
---
381
+
382
+
### Code Example
383
+
384
+
```js
385
+
let dat = {};
386
+
let modified = {};
387
+
let session =null;
388
+
389
+
functioninitdb() {
390
+
if (!file.exists("plugins/MyPlugin")) file.mkdir("plugins/MyPlugin");
// SQLite automatically adds a hidden ROWID column.
398
+
// insertId refers to this ROWID value.
399
+
}
100
400
101
-
### 📋 SQL Database
401
+
// Using do...while loop
402
+
functionloadData() {
403
+
let stmt =session.prepare("SELECT * FROM test");
404
+
// After prepare/execute, the cursor is already on the first row
405
+
do {
406
+
let row =stmt.fetch();
407
+
dat[row.player] =row.coins;
408
+
} while (stmt.step());
409
+
}
102
410
103
-
SQL databases are suitable for processing large amounts of relational data using SQL statements. The bottom layer of the interface is implemented using a cross-database operation framework, which can connect to most of the commonly used SQL databases in the market.
411
+
// Using callback function
412
+
functionloadData2() {
413
+
session.prepare("SELECT * FROM test")
414
+
.execute()
415
+
.fetchAll((row) => {
416
+
dat[row.player] =row.coins;
417
+
});
418
+
}
104
419
420
+
functionwriteData() {
421
+
let keys =Object.keys(modified);
422
+
let stmt =session.prepare("UPDATE test SET coins = ? WHERE player = ?");
423
+
for (let i =0; i <keys.length; i++) {
424
+
let v = modified[keys[i]];
425
+
// Automatically executes after binding if logic requires
426
+
stmt.bind([v, keys[i]]).execute();
427
+
stmt.clear(); // Clear values for next iteration
428
+
}
429
+
}
105
430
431
+
mc.regPlayerCmd("getcoin", "Get a coin!", (pl, args)=>{
0 commit comments