├── .github └── workflows │ └── release.yml ├── .gitignore ├── Makefile ├── README.md ├── libs ├── quickjs-libc.h ├── quickjs.c ├── quickjs.h ├── sqlite3.c ├── sqlite3.h └── sqlite3ext.h ├── src ├── sqlitejs.c └── sqlitejs.h └── test └── main.c /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release sqlite-js 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | permissions: 8 | contents: write 9 | 10 | jobs: 11 | build: 12 | runs-on: ${{ matrix.os }} 13 | name: ${{ matrix.name }}${{ matrix.arch && format('-{0}', matrix.arch) || '' }} build${{ matrix.arch != 'arm64-v8a' && matrix.name != 'isim' && matrix.name != 'ios' && ' + test' || ''}} 14 | timeout-minutes: 20 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | include: 19 | - os: macos-latest 20 | name: isim 21 | make: PLATFORM=isim 22 | - os: macos-latest 23 | name: ios 24 | make: PLATFORM=ios 25 | - os: ubuntu-latest 26 | arch: arm64-v8a 27 | name: android 28 | make: 29 | PLATFORM=android 30 | CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android26-clang 31 | - os: ubuntu-latest 32 | arch: x86_64 33 | name: android 34 | make: 35 | PLATFORM=android 36 | CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android26-clang 37 | sqlite-amalgamation-zip: https://sqlite.org/2025/sqlite-amalgamation-3490100.zip 38 | - os: ubuntu-latest 39 | arch: x86_64 40 | name: linux 41 | - os: LinuxARM64 42 | arch: arm64 43 | name: linux 44 | - os: macos-latest 45 | name: macos 46 | - os: windows-latest 47 | arch: x86_64 48 | name: windows 49 | 50 | defaults: 51 | run: 52 | shell: bash 53 | env: 54 | MAKEFLAGS: -j 8 55 | 56 | steps: 57 | 58 | - uses: actions/checkout@v4.2.2 59 | 60 | - name: build sqlite-js 61 | run: make ${{ matrix.make && matrix.make || ''}} 62 | 63 | - name: windows install sqlite3 64 | if: matrix.os == 'windows-latest' 65 | run: choco install sqlite -y 66 | 67 | - name: macos install sqlite3 without SQLITE_OMIT_LOAD_EXTENSION 68 | if: matrix.name == 'macos' 69 | run: brew link sqlite --force 70 | 71 | - name: android setup test environment 72 | if: matrix.name == 'android' && matrix.arch != 'arm64-v8a' 73 | run: | 74 | 75 | echo "::group::enable kvm group perms" 76 | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules 77 | sudo udevadm control --reload-rules 78 | sudo udevadm trigger --name-match=kvm 79 | echo "::endgroup::" 80 | 81 | echo "::group::download and build sqlite3 without SQLITE_OMIT_LOAD_EXTENSION" 82 | curl -O ${{ matrix.sqlite-amalgamation-zip }} 83 | unzip sqlite-amalgamation-*.zip 84 | export ${{ matrix.make }} 85 | $CC sqlite-amalgamation-*/shell.c sqlite-amalgamation-*/sqlite3.c -o sqlite3 -ldl 86 | rm -rf sqlite-amalgamation-*.zip sqlite-amalgamation-* 87 | echo "::endgroup::" 88 | 89 | echo "::group::prepare the test script" 90 | make test CC=$CC PLATFORM=$PLATFORM || echo "It should fail. Running remaining commands in the emulator" 91 | cat > commands.sh << EOF 92 | mv -f /data/local/tmp/sqlite3 /system/xbin 93 | cd /data/local/tmp 94 | $(make test CC=$CC PLATFORM=$PLATFORM -n) 95 | EOF 96 | echo "::endgroup::" 97 | 98 | - name: android test sqlite-js 99 | if: matrix.name == 'android' && matrix.arch != 'arm64-v8a' 100 | uses: reactivecircus/android-emulator-runner@v2.34.0 101 | with: 102 | api-level: 26 103 | arch: ${{ matrix.arch }} 104 | script: | 105 | adb root 106 | adb remount 107 | adb push ${{ github.workspace }}/. /data/local/tmp/ 108 | adb shell "sh /data/local/tmp/commands.sh" 109 | 110 | - name: test sqlite-js 111 | if: matrix.name == 'linux' || matrix.name == 'macos' || matrix.name == 'windows' 112 | run: make test 113 | 114 | - uses: actions/upload-artifact@v4.6.2 115 | with: 116 | name: js-${{ matrix.name }}${{ matrix.arch && format('-{0}', matrix.arch) || '' }} 117 | path: dist/js.* 118 | if-no-files-found: error 119 | 120 | release: 121 | runs-on: ubuntu-latest 122 | name: release 123 | needs: build 124 | 125 | env: 126 | GH_TOKEN: ${{ github.token }} 127 | 128 | steps: 129 | 130 | - uses: actions/checkout@v4.2.2 131 | 132 | - uses: actions/download-artifact@v4.2.1 133 | with: 134 | path: artifacts 135 | 136 | - name: release tag version from sqlitejs.h 137 | id: tag 138 | run: | 139 | FILE="src/sqlitejs.h" 140 | VERSION=$(grep -oP '#define SQLITE_JS_VERSION\s+"\K[^"]+' "$FILE") 141 | if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 142 | LATEST=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r '.name') 143 | if [[ "$VERSION" != "$LATEST" ]]; then 144 | echo "version=$VERSION" >> $GITHUB_OUTPUT 145 | else 146 | echo "::warning file=src/sqlitejs.h::To release a new version, please update the SQLITE_JS_VERSION in src/sqlitejs.h to be different than the latest $LATEST" 147 | fi 148 | exit 0 149 | fi 150 | echo "❌ SQLITE_JS_VERSION not found in sqlitejs.h" 151 | exit 1 152 | 153 | - name: zip artifacts 154 | run: | 155 | for folder in "artifacts"/*; do 156 | if [ -d "$folder" ]; then 157 | name=$(basename "$folder") 158 | zip -jq "${name}-${{ steps.tag.outputs.version }}.zip" "$folder"/* 159 | tar -cJf "${name}-${{ steps.tag.outputs.version }}.tar.xz" -C "$folder" . 160 | tar -czf "${name}-${{ steps.tag.outputs.version }}.tar.gz" -C "$folder" . 161 | fi 162 | done 163 | 164 | - uses: softprops/action-gh-release@v2.2.1 165 | if: steps.tag.outputs.version != '' 166 | with: 167 | generate_release_notes: true 168 | tag_name: ${{ steps.tag.outputs.version }} 169 | files: | 170 | js-*-${{ steps.tag.outputs.version }}.zip 171 | js-*-${{ steps.tag.outputs.version }}.tar.xz 172 | js-*-${{ steps.tag.outputs.version }}.tar.gz 173 | make_latest: true 174 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.xcworkspacedata 3 | *.xcuserstate 4 | *.xcbkptlist 5 | *.plist 6 | /build 7 | /dist 8 | *.sqlite -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for SQLite JavaScript Extension 2 | # Supports compilation for Linux, macOS, Windows, Android and iOS 3 | 4 | # Set default platform if not specified 5 | ifeq ($(OS),Windows_NT) 6 | PLATFORM := windows 7 | else 8 | UNAME_S := $(shell uname -s) 9 | ifeq ($(UNAME_S),Darwin) 10 | PLATFORM := macos 11 | else 12 | PLATFORM := linux 13 | endif 14 | endif 15 | 16 | # Directories 17 | SRC_DIR := src 18 | LIB_DIR := libs 19 | BUILD_DIR := build 20 | DIST_DIR := dist 21 | 22 | # Source files 23 | SRC_FILES := $(SRC_DIR)/sqlitejs.c $(LIB_DIR)/quickjs.c 24 | 25 | # Include directories 26 | INCLUDES := -I$(SRC_DIR) -I$(LIB_DIR) 27 | 28 | # Compiler and flags 29 | CC := gcc 30 | CFLAGS := -Wall -Wextra -fPIC -g -O2 -DQJS_BUILD_LIBC $(INCLUDES) 31 | 32 | # Platform-specific settings 33 | ifeq ($(PLATFORM),windows) 34 | TARGET := $(DIST_DIR)/js.dll 35 | LDFLAGS := -shared 36 | # Create .def file for Windows 37 | DEF_FILE := $(BUILD_DIR)/js.def 38 | else ifeq ($(PLATFORM),macos) 39 | TARGET := $(DIST_DIR)/js.dylib 40 | LDFLAGS := -arch x86_64 -arch arm64 -dynamiclib -undefined dynamic_lookup 41 | # macOS-specific flags 42 | CFLAGS += -arch x86_64 -arch arm64 43 | else ifeq ($(PLATFORM),android) 44 | # Use Android NDK's Clang compiler, the user should set the CC 45 | # example CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android26-clang 46 | ifeq ($(filter %-clang,$(CC)),) 47 | $(error "CC must be set to the Android NDK's Clang compiler") 48 | endif 49 | TARGET := $(DIST_DIR)/js.so 50 | LDFLAGS := -shared -lm 51 | # Android-specific flags 52 | CFLAGS += -D__ANDROID__ 53 | else ifeq ($(PLATFORM),ios) 54 | TARGET := $(DIST_DIR)/js.dylib 55 | SDK := -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -miphoneos-version-min=11.0 56 | LDFLAGS := -dynamiclib $(SDK) 57 | # iOS-specific flags 58 | CFLAGS += -arch arm64 $(SDK) 59 | else ifeq ($(PLATFORM),isim) 60 | TARGET := $(DIST_DIR)/js.dylib 61 | SDK := -isysroot $(shell xcrun --sdk iphonesimulator --show-sdk-path) -miphonesimulator-version-min=11.0 62 | LDFLAGS := -arch x86_64 -arch arm64 -dynamiclib $(SDK) 63 | # iphonesimulator-specific flags 64 | CFLAGS += -arch x86_64 -arch arm64 $(SDK) 65 | else # linux 66 | TARGET := $(DIST_DIR)/js.so 67 | LDFLAGS := -shared 68 | endif 69 | 70 | # Object files 71 | OBJ_FILES := $(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(SRC_FILES))) 72 | 73 | # Make sure the build and dist directories exist 74 | $(shell mkdir -p $(BUILD_DIR) $(DIST_DIR)) 75 | 76 | # Main target 77 | all: $(TARGET) 78 | 79 | # Link the final target 80 | $(TARGET): $(OBJ_FILES) $(DEF_FILE) 81 | $(CC) $(LDFLAGS) -o $@ $^ 82 | ifeq ($(PLATFORM),windows) 83 | # Generate import library for Windows 84 | dlltool -D $@ -d $(DEF_FILE) -l $(DIST_DIR)/js.lib 85 | endif 86 | 87 | # Compile source files 88 | $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c 89 | $(CC) $(CFLAGS) -c -o $@ $< 90 | 91 | $(BUILD_DIR)/%.o: $(LIB_DIR)/%.c 92 | $(CC) $(CFLAGS) -c -o $@ $< 93 | 94 | # Windows .def file generation 95 | $(DEF_FILE): 96 | ifeq ($(PLATFORM),windows) 97 | @echo "LIBRARY js.dll" > $@ 98 | @echo "EXPORTS" >> $@ 99 | @echo " sqlite3_js_init" >> $@ 100 | @echo " sqlitejs_version" >> $@ 101 | @echo " quickjs_version" >> $@ 102 | endif 103 | 104 | # Clean up 105 | clean: 106 | rm -rf $(BUILD_DIR)/* $(DIST_DIR)/* 107 | 108 | # Install the extension (adjust paths as needed) 109 | install: $(TARGET) 110 | ifeq ($(PLATFORM),windows) 111 | mkdir -p $(DESTDIR)/usr/local/lib/sqlite3 112 | cp $(TARGET) $(DESTDIR)/usr/local/lib/sqlite3/ 113 | cp $(DIST_DIR)/js.lib $(DESTDIR)/usr/local/lib/ 114 | else ifeq ($(PLATFORM),macos) 115 | mkdir -p $(DESTDIR)/usr/local/lib/sqlite3 116 | cp $(TARGET) $(DESTDIR)/usr/local/lib/sqlite3/ 117 | else # linux 118 | mkdir -p $(DESTDIR)/usr/local/lib/sqlite3 119 | cp $(TARGET) $(DESTDIR)/usr/local/lib/sqlite3/ 120 | endif 121 | 122 | # Test source files 123 | TEST_FILES := test/main.c 124 | 125 | # Test target files 126 | ifeq ($(PLATFORM),windows) 127 | TEST_TARGET := $(patsubst %.c,$(DIST_DIR)/%.exe,$(notdir $(TEST_FILES))) 128 | else 129 | TEST_TARGET := $(patsubst %.c,$(DIST_DIR)/%,$(notdir $(TEST_FILES))) 130 | endif 131 | 132 | # Compile test target 133 | $(TEST_TARGET): $(TEST_FILES) $(TARGET) 134 | $(CC) $(INCLUDES) $^ -lm -o $@ libs/sqlite3.c -DSQLITE_CORE 135 | 136 | # Testing the extension 137 | test: $(TARGET) $(TEST_TARGET) 138 | sqlite3 ":memory:" -cmd ".bail on" ".load ./$<" "SELECT js_eval('console.log(\"hello, world\nToday is\", new Date().toLocaleDateString())');" 139 | ./$(TEST_TARGET) 140 | 141 | # Help message 142 | help: 143 | @echo "SQLite JavaScript Extension Makefile" 144 | @echo "Usage:" 145 | @echo " make [PLATFORM=platform] [target]" 146 | @echo "" 147 | @echo "Platforms:" 148 | @echo " linux (default on Linux)" 149 | @echo " macos (default on macOS)" 150 | @echo " windows (default on Windows)" 151 | @echo " android (needs CC to be set to Android NDK's Clang compiler)" 152 | @echo " ios (only on macOS)" 153 | @echo " isim (only on macOS)" 154 | @echo "" 155 | @echo "Targets:" 156 | @echo " all - Build the extension (default)" 157 | @echo " clean - Remove built files" 158 | @echo " install - Install the extension" 159 | @echo " test - Test the extension" 160 | @echo " help - Display this help message" 161 | 162 | .PHONY: all clean install test help 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SQLite-JS Extension 2 | 3 | SQLite-JS is a powerful extension that brings JavaScript capabilities to SQLite. With this extension, you can create custom SQLite functions, aggregates, window functions, and collation sequences using JavaScript code, allowing for flexible and powerful data manipulation directly within your SQLite database. 4 | 5 | ## Table of Contents 6 | 7 | - [Installation](#installation) 8 | - [Functions Overview](#functions-overview) 9 | - [Scalar Functions](#scalar-functions) 10 | - [Aggregate Functions](#aggregate-functions) 11 | - [Window Functions](#window-functions) 12 | - [Collation Sequences](#collation-sequences) 13 | - [Sync JavaScript Functions Across Devices](#syncing-across-devices) 14 | - [JavaScript Evaluation](#javascript-evaluation) 15 | - [Examples](#examples) 16 | - [Update Functions](#update-functions) 17 | - [Building from Source](#building-from-source) 18 | - [License](#license) 19 | 20 | ## Installation 21 | 22 | ### Pre-built Binaries 23 | 24 | Download the appropriate pre-built binary for your platform from the official [Releases](https://github.com/sqliteai/sqlite-js/releases) page: 25 | 26 | - Linux: x86 and ARM 27 | - macOS: x86 and ARM 28 | - Windows: x86 29 | - Android 30 | - iOS 31 | 32 | ### Loading the Extension 33 | 34 | ```sql 35 | -- In SQLite CLI 36 | .load ./js 37 | 38 | -- In SQL 39 | SELECT load_extension('./js'); 40 | ``` 41 | 42 | ## Functions Overview 43 | 44 | SQLite-JS provides several ways to extend SQLite functionality with JavaScript: 45 | 46 | | Function Type | Description | 47 | |---------------|-------------| 48 | | Scalar Functions | Process individual rows and return a single value | 49 | | Aggregate Functions | Process multiple rows and return a single aggregated result | 50 | | Window Functions | Similar to aggregates but can access the full dataset | 51 | | Collation Sequences | Define custom sort orders for text values | 52 | | JavaScript Evaluation | Directly evaluate JavaScript code within SQLite | 53 | 54 | ## Scalar Functions 55 | 56 | Scalar functions process one row at a time and return a single value. They are useful for data transformation, calculations, text manipulation, etc. 57 | 58 | ### Usage 59 | 60 | ```sql 61 | SELECT js_create_scalar('function_name', 'function_code'); 62 | ``` 63 | 64 | ### Parameters 65 | 66 | - **function_name**: The name of your custom function 67 | - **function_code**: JavaScript code that defines your function. Must be in the form `function(args) { /* your code here */ }` 68 | 69 | ### Example 70 | 71 | ```sql 72 | -- Create a custom function to calculate age from birth date 73 | SELECT js_create_scalar('age', 'function(args) { 74 | const birthDate = new Date(args[0]); 75 | const today = new Date(); 76 | let age = today.getFullYear() - birthDate.getFullYear(); 77 | const m = today.getMonth() - birthDate.getMonth(); 78 | if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) { 79 | age--; 80 | } 81 | return age; 82 | }'); 83 | 84 | -- Use the function 85 | SELECT name, age(birth_date) FROM people; 86 | ``` 87 | 88 | ## Aggregate Functions 89 | 90 | Aggregate functions process multiple rows and compute a single result. Examples include SUM, AVG, and COUNT in standard SQL. 91 | 92 | ### Usage 93 | 94 | ```sql 95 | SELECT js_create_aggregate('function_name', 'init_code', 'step_code', 'final_code'); 96 | ``` 97 | 98 | ### Parameters 99 | 100 | - **function_name**: The name of your custom aggregate function 101 | - **init_code**: JavaScript code that initializes variables for the aggregation 102 | - **step_code**: JavaScript code that processes each row. Must be in the form `function(args) { /* your code here */ }` 103 | - **final_code**: JavaScript code that computes the final result. Must be in the form `function() { /* your code here */ }` 104 | 105 | ### Example 106 | 107 | ```sql 108 | -- Create a median function 109 | SELECT js_create_aggregate('median', 110 | -- Init code: initialize an array to store values 111 | 'values = [];', 112 | 113 | -- Step code: collect values from each row 114 | 'function(args) { 115 | values.push(args[0]); 116 | }', 117 | 118 | -- Final code: calculate the median 119 | 'function() { 120 | values.sort((a, b) => a - b); 121 | const mid = Math.floor(values.length / 2); 122 | if (values.length % 2 === 0) { 123 | return (values[mid-1] + values[mid]) / 2; 124 | } else { 125 | return values[mid]; 126 | } 127 | }' 128 | ); 129 | 130 | -- Use the function 131 | SELECT median(salary) FROM employees; 132 | ``` 133 | 134 | ## Window Functions 135 | 136 | Window functions, like aggregate functions, operate on a set of rows. However, they can access all rows in the current window without collapsing them into a single output row. 137 | 138 | ### Usage 139 | 140 | ```sql 141 | SELECT js_create_window('function_name', 'init_code', 'step_code', 'final_code', 'value_code', 'inverse_code'); 142 | ``` 143 | 144 | ### Parameters 145 | 146 | - **function_name**: The name of your custom window function 147 | - **init_code**: JavaScript code that initializes variables 148 | - **step_code**: JavaScript code that processes each row. Must be in the form `function(args) { /* your code here */ }` 149 | - **final_code**: JavaScript code that computes the final result. Must be in the form `function() { /* your code here */ }` 150 | - **value_code**: JavaScript code that returns the current value. Must be in the form `function() { /* your code here */ }` 151 | - **inverse_code**: JavaScript code that removes a row from the current window. Must be in the form `function(args) { /* your code here */ }` 152 | 153 | ### Example 154 | 155 | ```sql 156 | -- Create a moving average window function 157 | SELECT js_create_window('moving_avg', 158 | -- Init code 159 | 'sum = 0; count = 0;', 160 | 161 | -- Step code: process each row 162 | 'function(args) { 163 | sum += args[0]; 164 | count++; 165 | }', 166 | 167 | -- Final code: not needed for this example 168 | 'function() { }', 169 | 170 | -- Value code: return current average 171 | 'function() { 172 | return count > 0 ? sum / count : null; 173 | }', 174 | 175 | -- Inverse code: remove a value from the window 176 | 'function(args) { 177 | sum -= args[0]; 178 | count--; 179 | }' 180 | ); 181 | 182 | -- Use the function 183 | SELECT id, value, moving_avg(value) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) 184 | FROM measurements; 185 | ``` 186 | 187 | ## Collation Sequences 188 | 189 | Collation sequences determine how text values are compared and sorted in SQLite. Custom collations enable advanced sorting capabilities like natural sorting, locale-specific sorting, etc. 190 | 191 | ### Usage 192 | 193 | ```sql 194 | SELECT js_create_collation('collation_name', 'collation_function'); 195 | ``` 196 | 197 | ### Parameters 198 | 199 | - **collation_name**: The name of your custom collation 200 | - **collation_function**: JavaScript code that compares two strings. Must return a negative number if the first string is less than the second, zero if they are equal, or a positive number if the first string is greater than the second. 201 | 202 | ### Example 203 | 204 | ```sql 205 | -- Create a case-insensitive natural sort collation 206 | SELECT js_create_collation('natural_nocase', 'function(a, b) { 207 | // Extract numbers for natural comparison 208 | const splitA = a.toLowerCase().split(/(\d+)/); 209 | const splitB = b.toLowerCase().split(/(\d+)/); 210 | 211 | for (let i = 0; i < Math.min(splitA.length, splitB.length); i++) { 212 | if (splitA[i] !== splitB[i]) { 213 | if (!isNaN(splitA[i]) && !isNaN(splitB[i])) { 214 | return parseInt(splitA[i]) - parseInt(splitB[i]); 215 | } 216 | return splitA[i].localeCompare(splitB[i]); 217 | } 218 | } 219 | return splitA.length - splitB.length; 220 | }'); 221 | 222 | -- Use the collation 223 | SELECT * FROM files ORDER BY name COLLATE natural_nocase; 224 | ``` 225 | 226 | ## Syncing Across Devices 227 | 228 | When used with [sqlite-sync](https://github.com/sqliteai/sqlite-sync/), user-defined functions created via sqlite-js are automatically replicated across the SQLite Cloud cluster, ensuring that all connected peers share the same logic and behavior — even offline. To enable automatic persistence and sync the special `js_init_table` function must be executed. 229 | 230 | ### Usage 231 | ```sql 232 | SELECT js_init_table(); -- Create table if needed (no loading) 233 | SELECT js_init_table(1); -- Create table and load all stored functions 234 | ``` 235 | 236 | ## JavaScript Evaluation 237 | 238 | The extension also provides a way to directly evaluate JavaScript code within SQLite queries. 239 | 240 | ### Usage 241 | 242 | ```sql 243 | SELECT js_eval('javascript_code'); 244 | ``` 245 | 246 | ### Parameters 247 | 248 | - **javascript_code**: Any valid JavaScript code to evaluate 249 | 250 | ### Example 251 | 252 | ```sql 253 | -- Perform a calculation 254 | SELECT js_eval('Math.PI * Math.pow(5, 2)'); 255 | 256 | -- Format a date 257 | SELECT js_eval('new Date(1629381600000).toLocaleDateString()'); 258 | ``` 259 | 260 | ## Examples 261 | 262 | ### Example 1: String Manipulation 263 | 264 | ```sql 265 | -- Create a function to extract domain from email 266 | SELECT js_create_scalar('get_domain', 'function(args) { 267 | const email = args[0]; 268 | return email.split("@")[1] || null; 269 | }'); 270 | 271 | -- Use it in a query 272 | SELECT email, get_domain(email) AS domain FROM users; 273 | ``` 274 | 275 | ### Example 2: Statistical Aggregation 276 | 277 | ```sql 278 | -- Create a function to calculate standard deviation 279 | SELECT js_create_aggregate('stddev', 280 | 'sum = 0; sumSq = 0; count = 0;', 281 | 282 | 'function(args) { 283 | const val = args[0]; 284 | sum += val; 285 | sumSq += val * val; 286 | count++; 287 | }', 288 | 289 | 'function() { 290 | if (count < 2) return null; 291 | const variance = (sumSq - (sum * sum) / count) / (count - 1); 292 | return Math.sqrt(variance); 293 | }' 294 | ); 295 | 296 | -- Use it in a query 297 | SELECT department, stddev(salary) FROM employees GROUP BY department; 298 | ``` 299 | 300 | ### Example 3: Custom Window Function 301 | 302 | ```sql 303 | -- Create a window function to calculate percentile within a window 304 | SELECT js_create_window('percentile_rank', 305 | 'values = [];', 306 | 307 | 'function(args) { 308 | values.push(args[0]); 309 | }', 310 | 311 | 'function() { 312 | values.sort((a, b) => a - b); 313 | }', 314 | 315 | 'function() { 316 | const current = values[values.length - 1]; 317 | const rank = values.indexOf(current); 318 | return (rank / (values.length - 1)) * 100; 319 | }', 320 | 321 | 'function(args) { 322 | const index = values.indexOf(args[0]); 323 | if (index !== -1) { 324 | values.splice(index, 1); 325 | } 326 | }' 327 | ); 328 | 329 | -- Use it in a query 330 | SELECT name, score, 331 | percentile_rank(score) OVER (ORDER BY score) 332 | FROM exam_results; 333 | ``` 334 | 335 | ## Update Functions 336 | 337 | Due to a constraint in [SQLite](https://www3.sqlite.org/src/info/cabab62bc10568d4), it is not possible to update or redefine a user-defined function using the same database connection that was used to initially register it. To modify an existing JavaScript function, the update must be performed through a separate database connection. 338 | 339 | ## Building from Source 340 | 341 | See the included Makefile for building instructions: 342 | 343 | ```bash 344 | # Build for your current platform 345 | make 346 | 347 | # Build for a specific platform 348 | make PLATFORM=macos 349 | make PLATFORM=linux 350 | make PLATFORM=windows 351 | 352 | # Install 353 | make install 354 | ``` 355 | 356 | ## License 357 | 358 | This project is licensed under the MIT License - see the LICENSE file for details. 359 | -------------------------------------------------------------------------------- /libs/quickjs-libc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS C library 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef QUICKJS_LIBC_H 25 | #define QUICKJS_LIBC_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "quickjs.h" 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); 38 | JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); 39 | JSModuleDef *js_init_module_bjson(JSContext *ctx, const char *module_name); 40 | void js_std_add_helpers(JSContext *ctx, int argc, char **argv); 41 | int js_std_loop(JSContext *ctx); 42 | JSValue js_std_await(JSContext *ctx, JSValue obj); 43 | void js_std_init_handlers(JSRuntime *rt); 44 | void js_std_free_handlers(JSRuntime *rt); 45 | void js_std_dump_error(JSContext *ctx); 46 | uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); 47 | int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, 48 | bool use_realpath, bool is_main); 49 | JSModuleDef *js_module_loader(JSContext *ctx, 50 | const char *module_name, void *opaque); 51 | void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, 52 | int flags); 53 | void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, 54 | JSValueConst reason, 55 | bool is_handled, void *opaque); 56 | void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)); 57 | 58 | #ifdef __cplusplus 59 | } /* extern "C" { */ 60 | #endif 61 | 62 | #endif /* QUICKJS_LIBC_H */ 63 | -------------------------------------------------------------------------------- /libs/quickjs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS Javascript Engine 3 | * 4 | * Copyright (c) 2017-2024 Fabrice Bellard 5 | * Copyright (c) 2017-2024 Charlie Gordon 6 | * Copyright (c) 2023-2025 Ben Noordhuis 7 | * Copyright (c) 2023-2025 Saúl Ibarra Corretgé 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | #ifndef QUICKJS_H 28 | #define QUICKJS_H 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | #define QUICKJS_NG 1 41 | 42 | #if defined(__GNUC__) || defined(__clang__) 43 | #define js_force_inline inline __attribute__((always_inline)) 44 | #define JS_EXTERN __attribute__((visibility("default"))) 45 | #else 46 | #define js_force_inline inline 47 | #define JS_EXTERN /* nothing */ 48 | #endif 49 | 50 | /* Borrowed from Folly */ 51 | #ifndef JS_PRINTF_FORMAT 52 | #ifdef _MSC_VER 53 | #include 54 | #define JS_PRINTF_FORMAT _Printf_format_string_ 55 | #define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) 56 | #else 57 | #define JS_PRINTF_FORMAT 58 | #if !defined(__clang__) && defined(__GNUC__) 59 | #define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \ 60 | __attribute__((format(gnu_printf, format_param, dots_param))) 61 | #else 62 | #define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \ 63 | __attribute__((format(printf, format_param, dots_param))) 64 | #endif 65 | #endif 66 | #endif 67 | 68 | typedef struct JSRuntime JSRuntime; 69 | typedef struct JSContext JSContext; 70 | typedef struct JSObject JSObject; 71 | typedef struct JSClass JSClass; 72 | typedef uint32_t JSClassID; 73 | typedef uint32_t JSAtom; 74 | 75 | /* Unless documented otherwise, C string pointers (`char *` or `const char *`) 76 | are assumed to verify these constraints: 77 | - unless a length is passed separately, the string has a null terminator 78 | - string contents is either pure ASCII or is UTF-8 encoded. 79 | */ 80 | 81 | /* Overridable purely for testing purposes; don't touch. */ 82 | #ifndef JS_NAN_BOXING 83 | #if INTPTR_MAX < INT64_MAX 84 | #define JS_NAN_BOXING 1 /* Use NAN boxing for 32bit builds. */ 85 | #endif 86 | #endif 87 | 88 | enum { 89 | /* all tags with a reference count are negative */ 90 | JS_TAG_FIRST = -9, /* first negative tag */ 91 | JS_TAG_BIG_INT = -9, 92 | JS_TAG_SYMBOL = -8, 93 | JS_TAG_STRING = -7, 94 | JS_TAG_MODULE = -3, /* used internally */ 95 | JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */ 96 | JS_TAG_OBJECT = -1, 97 | 98 | JS_TAG_INT = 0, 99 | JS_TAG_BOOL = 1, 100 | JS_TAG_NULL = 2, 101 | JS_TAG_UNDEFINED = 3, 102 | JS_TAG_UNINITIALIZED = 4, 103 | JS_TAG_CATCH_OFFSET = 5, 104 | JS_TAG_EXCEPTION = 6, 105 | JS_TAG_FLOAT64 = 7, 106 | /* any larger tag is FLOAT64 if JS_NAN_BOXING */ 107 | }; 108 | 109 | #if !defined(JS_CHECK_JSVALUE) 110 | #define JSValueConst JSValue 111 | #endif 112 | 113 | // JS_CHECK_JSVALUE build mode does not produce working code but is here to 114 | // help catch reference counting bugs at compile time, by making it harder 115 | // to mix up JSValue and JSValueConst 116 | // 117 | // rules: 118 | // 119 | // - a function with a JSValue parameter takes ownership; 120 | // caller must *not* call JS_FreeValue 121 | // 122 | // - a function with a JSValueConst parameter does not take ownership; 123 | // caller *must* call JS_FreeValue 124 | // 125 | // - a function returning a JSValue transfers ownership to caller; 126 | // caller *must* call JS_FreeValue 127 | // 128 | // - a function returning a JSValueConst does *not* transfer ownership; 129 | // caller must *not* call JS_FreeValue 130 | #if defined(JS_CHECK_JSVALUE) 131 | 132 | typedef struct JSValue *JSValue; 133 | typedef const struct JSValue *JSValueConst; 134 | 135 | #define JS_MKVAL(tag, val) ((JSValue)((tag) | (intptr_t)(val) << 4)) 136 | #define JS_MKPTR(tag, ptr) ((JSValue)((tag) | (intptr_t)(ptr))) 137 | #define JS_VALUE_GET_NORM_TAG(v) ((int)((intptr_t)(v) & 15)) 138 | #define JS_VALUE_GET_TAG(v) ((int)((intptr_t)(v) & 15)) 139 | #define JS_VALUE_GET_PTR(v) ((void *)((intptr_t)(v) & ~15)) 140 | #define JS_VALUE_GET_INT(v) ((int)((intptr_t)(v) >> 4)) 141 | #define JS_VALUE_GET_BOOL(v) ((int)((intptr_t)(v) >> 4)) 142 | #define JS_VALUE_GET_FLOAT64(v) ((double)((intptr_t)(v) >> 4)) 143 | #define JS_TAG_IS_FLOAT64(tag) ((int)(tag) == JS_TAG_FLOAT64) 144 | #define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 0) 145 | 146 | static inline JSValue __JS_NewFloat64(double d) 147 | { 148 | return JS_MKVAL(JS_TAG_FLOAT64, (int)d); 149 | } 150 | 151 | static inline bool JS_VALUE_IS_NAN(JSValue v) 152 | { 153 | (void)&v; 154 | return false; 155 | } 156 | 157 | #elif defined(JS_NAN_BOXING) && JS_NAN_BOXING 158 | 159 | typedef uint64_t JSValue; 160 | 161 | #define JS_VALUE_GET_TAG(v) (int)((v) >> 32) 162 | #define JS_VALUE_GET_INT(v) (int)(v) 163 | #define JS_VALUE_GET_BOOL(v) (int)(v) 164 | #define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v) 165 | 166 | #define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val)) 167 | #define JS_MKPTR(tag, ptr) (((uint64_t)(tag) << 32) | (uintptr_t)(ptr)) 168 | 169 | #define JS_FLOAT64_TAG_ADDEND (0x7ff80000 - JS_TAG_FIRST + 1) /* quiet NaN encoding */ 170 | 171 | static inline double JS_VALUE_GET_FLOAT64(JSValue v) 172 | { 173 | union { 174 | JSValue v; 175 | double d; 176 | } u; 177 | u.v = v; 178 | u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32; 179 | return u.d; 180 | } 181 | 182 | #define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32)) 183 | 184 | static inline JSValue __JS_NewFloat64(double d) 185 | { 186 | union { 187 | double d; 188 | uint64_t u64; 189 | } u; 190 | JSValue v; 191 | u.d = d; 192 | /* normalize NaN */ 193 | if ((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000) 194 | v = JS_NAN; 195 | else 196 | v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32); 197 | return v; 198 | } 199 | 200 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag) - JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST)) 201 | 202 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 203 | static inline int JS_VALUE_GET_NORM_TAG(JSValue v) 204 | { 205 | uint32_t tag; 206 | tag = JS_VALUE_GET_TAG(v); 207 | if (JS_TAG_IS_FLOAT64(tag)) 208 | return JS_TAG_FLOAT64; 209 | else 210 | return tag; 211 | } 212 | 213 | static inline bool JS_VALUE_IS_NAN(JSValue v) 214 | { 215 | uint32_t tag; 216 | tag = JS_VALUE_GET_TAG(v); 217 | return tag == (JS_NAN >> 32); 218 | } 219 | 220 | #else /* !JS_NAN_BOXING */ 221 | 222 | typedef union JSValueUnion { 223 | int32_t int32; 224 | double float64; 225 | void *ptr; 226 | } JSValueUnion; 227 | 228 | typedef struct JSValue { 229 | JSValueUnion u; 230 | int64_t tag; 231 | } JSValue; 232 | 233 | #define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag) 234 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 235 | #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) 236 | #define JS_VALUE_GET_INT(v) ((v).u.int32) 237 | #define JS_VALUE_GET_BOOL(v) ((v).u.int32) 238 | #define JS_VALUE_GET_FLOAT64(v) ((v).u.float64) 239 | #define JS_VALUE_GET_PTR(v) ((v).u.ptr) 240 | 241 | /* msvc doesn't understand designated initializers without /std:c++20 */ 242 | #ifdef __cplusplus 243 | static inline JSValue JS_MKPTR(int64_t tag, void *ptr) 244 | { 245 | JSValue v; 246 | v.u.ptr = ptr; 247 | v.tag = tag; 248 | return v; 249 | } 250 | static inline JSValue JS_MKVAL(int64_t tag, int32_t int32) 251 | { 252 | JSValue v; 253 | v.u.int32 = int32; 254 | v.tag = tag; 255 | return v; 256 | } 257 | static inline JSValue JS_MKNAN(void) 258 | { 259 | JSValue v; 260 | v.u.float64 = NAN; 261 | v.tag = JS_TAG_FLOAT64; 262 | return v; 263 | } 264 | /* provide as macros for consistency and backward compat reasons */ 265 | #define JS_MKPTR(tag, ptr) JS_MKPTR(tag, ptr) 266 | #define JS_MKVAL(tag, val) JS_MKVAL(tag, val) 267 | #define JS_NAN JS_MKNAN() /* alas, not a constant expression */ 268 | #else 269 | #define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag } 270 | #define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag } 271 | #define JS_NAN (JSValue){ (JSValueUnion){ .float64 = NAN }, JS_TAG_FLOAT64 } 272 | #endif 273 | 274 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) 275 | 276 | static inline JSValue __JS_NewFloat64(double d) 277 | { 278 | JSValue v; 279 | v.tag = JS_TAG_FLOAT64; 280 | v.u.float64 = d; 281 | return v; 282 | } 283 | 284 | static inline bool JS_VALUE_IS_NAN(JSValue v) 285 | { 286 | union { 287 | double d; 288 | uint64_t u64; 289 | } u; 290 | if (v.tag != JS_TAG_FLOAT64) 291 | return 0; 292 | u.d = v.u.float64; 293 | return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000; 294 | } 295 | 296 | #endif /* !JS_NAN_BOXING */ 297 | 298 | #define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0) 299 | #define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2))) 300 | 301 | #define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v)) 302 | #define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST) 303 | 304 | /* special values */ 305 | #define JS_NULL JS_MKVAL(JS_TAG_NULL, 0) 306 | #define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0) 307 | #define JS_FALSE JS_MKVAL(JS_TAG_BOOL, 0) 308 | #define JS_TRUE JS_MKVAL(JS_TAG_BOOL, 1) 309 | #define JS_EXCEPTION JS_MKVAL(JS_TAG_EXCEPTION, 0) 310 | #define JS_UNINITIALIZED JS_MKVAL(JS_TAG_UNINITIALIZED, 0) 311 | 312 | /* flags for object properties */ 313 | #define JS_PROP_CONFIGURABLE (1 << 0) 314 | #define JS_PROP_WRITABLE (1 << 1) 315 | #define JS_PROP_ENUMERABLE (1 << 2) 316 | #define JS_PROP_C_W_E (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE) 317 | #define JS_PROP_LENGTH (1 << 3) /* used internally in Arrays */ 318 | #define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, GETSET, VARREF, AUTOINIT */ 319 | #define JS_PROP_NORMAL (0 << 4) 320 | #define JS_PROP_GETSET (1 << 4) 321 | #define JS_PROP_VARREF (2 << 4) /* used internally */ 322 | #define JS_PROP_AUTOINIT (3 << 4) /* used internally */ 323 | 324 | /* flags for JS_DefineProperty */ 325 | #define JS_PROP_HAS_SHIFT 8 326 | #define JS_PROP_HAS_CONFIGURABLE (1 << 8) 327 | #define JS_PROP_HAS_WRITABLE (1 << 9) 328 | #define JS_PROP_HAS_ENUMERABLE (1 << 10) 329 | #define JS_PROP_HAS_GET (1 << 11) 330 | #define JS_PROP_HAS_SET (1 << 12) 331 | #define JS_PROP_HAS_VALUE (1 << 13) 332 | 333 | /* throw an exception if false would be returned 334 | (JS_DefineProperty/JS_SetProperty) */ 335 | #define JS_PROP_THROW (1 << 14) 336 | /* throw an exception if false would be returned in strict mode 337 | (JS_SetProperty) */ 338 | #define JS_PROP_THROW_STRICT (1 << 15) 339 | 340 | #define JS_PROP_NO_ADD (1 << 16) /* internal use */ 341 | #define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */ 342 | #define JS_PROP_DEFINE_PROPERTY (1 << 18) /* internal use */ 343 | #define JS_PROP_REFLECT_DEFINE_PROPERTY (1 << 19) /* internal use */ 344 | 345 | #ifndef JS_DEFAULT_STACK_SIZE 346 | #define JS_DEFAULT_STACK_SIZE (1024 * 1024) 347 | #endif 348 | 349 | /* JS_Eval() flags */ 350 | #define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */ 351 | #define JS_EVAL_TYPE_MODULE (1 << 0) /* module code */ 352 | #define JS_EVAL_TYPE_DIRECT (2 << 0) /* direct call (internal use) */ 353 | #define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */ 354 | #define JS_EVAL_TYPE_MASK (3 << 0) 355 | 356 | #define JS_EVAL_FLAG_STRICT (1 << 3) /* force 'strict' mode */ 357 | #define JS_EVAL_FLAG_UNUSED (1 << 4) /* unused */ 358 | /* compile but do not run. The result is an object with a 359 | JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed 360 | with JS_EvalFunction(). */ 361 | #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) 362 | /* don't include the stack frames before this eval in the Error() backtraces */ 363 | #define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) 364 | /* allow top-level await in normal script. JS_Eval() returns a 365 | promise. Only allowed with JS_EVAL_TYPE_GLOBAL */ 366 | #define JS_EVAL_FLAG_ASYNC (1 << 7) 367 | 368 | typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); 369 | typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); 370 | typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValueConst *func_data); 371 | 372 | typedef struct JSMallocFunctions { 373 | void *(*js_calloc)(void *opaque, size_t count, size_t size); 374 | void *(*js_malloc)(void *opaque, size_t size); 375 | void (*js_free)(void *opaque, void *ptr); 376 | void *(*js_realloc)(void *opaque, void *ptr, size_t size); 377 | size_t (*js_malloc_usable_size)(const void *ptr); 378 | } JSMallocFunctions; 379 | 380 | // Debug trace system: the debug output will be produced to the dump stream (currently 381 | // stdout) if dumps are enabled and JS_SetDumpFlags is invoked with the corresponding 382 | // bit set. 383 | #define JS_DUMP_BYTECODE_FINAL 0x01 /* dump pass 3 final byte code */ 384 | #define JS_DUMP_BYTECODE_PASS2 0x02 /* dump pass 2 code */ 385 | #define JS_DUMP_BYTECODE_PASS1 0x04 /* dump pass 1 code */ 386 | #define JS_DUMP_BYTECODE_HEX 0x10 /* dump bytecode in hex */ 387 | #define JS_DUMP_BYTECODE_PC2LINE 0x20 /* dump line number table */ 388 | #define JS_DUMP_BYTECODE_STACK 0x40 /* dump compute_stack_size */ 389 | #define JS_DUMP_BYTECODE_STEP 0x80 /* dump executed bytecode */ 390 | #define JS_DUMP_READ_OBJECT 0x100 /* dump the marshalled objects at load time */ 391 | #define JS_DUMP_FREE 0x200 /* dump every object free */ 392 | #define JS_DUMP_GC 0x400 /* dump the occurrence of the automatic GC */ 393 | #define JS_DUMP_GC_FREE 0x800 /* dump objects freed by the GC */ 394 | #define JS_DUMP_MODULE_RESOLVE 0x1000 /* dump module resolution steps */ 395 | #define JS_DUMP_PROMISE 0x2000 /* dump promise steps */ 396 | #define JS_DUMP_LEAKS 0x4000 /* dump leaked objects and strings in JS_FreeRuntime */ 397 | #define JS_DUMP_ATOM_LEAKS 0x8000 /* dump leaked atoms in JS_FreeRuntime */ 398 | #define JS_DUMP_MEM 0x10000 /* dump memory usage in JS_FreeRuntime */ 399 | #define JS_DUMP_OBJECTS 0x20000 /* dump objects in JS_FreeRuntime */ 400 | #define JS_DUMP_ATOMS 0x40000 /* dump atoms in JS_FreeRuntime */ 401 | #define JS_DUMP_SHAPES 0x80000 /* dump shapes in JS_FreeRuntime */ 402 | 403 | // Finalizers run in LIFO order at the very end of JS_FreeRuntime. 404 | // Intended for cleanup of associated resources; the runtime itself 405 | // is no longer usable. 406 | typedef void JSRuntimeFinalizer(JSRuntime *rt, void *arg); 407 | 408 | typedef struct JSGCObjectHeader JSGCObjectHeader; 409 | 410 | JS_EXTERN JSRuntime *JS_NewRuntime(void); 411 | /* info lifetime must exceed that of rt */ 412 | JS_EXTERN void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); 413 | /* use 0 to disable memory limit */ 414 | JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); 415 | JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags); 416 | JS_EXTERN uint64_t JS_GetDumpFlags(JSRuntime *rt); 417 | JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt); 418 | JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); 419 | /* use 0 to disable maximum stack size check */ 420 | JS_EXTERN void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); 421 | /* should be called when changing thread to update the stack top value 422 | used to check stack overflow. */ 423 | JS_EXTERN void JS_UpdateStackTop(JSRuntime *rt); 424 | JS_EXTERN JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque); 425 | JS_EXTERN void JS_FreeRuntime(JSRuntime *rt); 426 | JS_EXTERN void *JS_GetRuntimeOpaque(JSRuntime *rt); 427 | JS_EXTERN void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque); 428 | JS_EXTERN int JS_AddRuntimeFinalizer(JSRuntime *rt, 429 | JSRuntimeFinalizer *finalizer, void *arg); 430 | typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp); 431 | JS_EXTERN void JS_MarkValue(JSRuntime *rt, JSValueConst val, 432 | JS_MarkFunc *mark_func); 433 | JS_EXTERN void JS_RunGC(JSRuntime *rt); 434 | JS_EXTERN bool JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); 435 | 436 | JS_EXTERN JSContext *JS_NewContext(JSRuntime *rt); 437 | JS_EXTERN void JS_FreeContext(JSContext *s); 438 | JS_EXTERN JSContext *JS_DupContext(JSContext *ctx); 439 | JS_EXTERN void *JS_GetContextOpaque(JSContext *ctx); 440 | JS_EXTERN void JS_SetContextOpaque(JSContext *ctx, void *opaque); 441 | JS_EXTERN JSRuntime *JS_GetRuntime(JSContext *ctx); 442 | JS_EXTERN void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); 443 | JS_EXTERN JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); 444 | JS_EXTERN JSValue JS_GetFunctionProto(JSContext *ctx); 445 | 446 | /* the following functions are used to select the intrinsic object to 447 | save memory */ 448 | JS_EXTERN JSContext *JS_NewContextRaw(JSRuntime *rt); 449 | JS_EXTERN void JS_AddIntrinsicBaseObjects(JSContext *ctx); 450 | JS_EXTERN void JS_AddIntrinsicDate(JSContext *ctx); 451 | JS_EXTERN void JS_AddIntrinsicEval(JSContext *ctx); 452 | JS_EXTERN void JS_AddIntrinsicRegExpCompiler(JSContext *ctx); 453 | JS_EXTERN void JS_AddIntrinsicRegExp(JSContext *ctx); 454 | JS_EXTERN void JS_AddIntrinsicJSON(JSContext *ctx); 455 | JS_EXTERN void JS_AddIntrinsicProxy(JSContext *ctx); 456 | JS_EXTERN void JS_AddIntrinsicMapSet(JSContext *ctx); 457 | JS_EXTERN void JS_AddIntrinsicTypedArrays(JSContext *ctx); 458 | JS_EXTERN void JS_AddIntrinsicPromise(JSContext *ctx); 459 | JS_EXTERN void JS_AddIntrinsicBigInt(JSContext *ctx); 460 | JS_EXTERN void JS_AddIntrinsicWeakRef(JSContext *ctx); 461 | JS_EXTERN void JS_AddPerformance(JSContext *ctx); 462 | 463 | /* for equality comparisons and sameness */ 464 | JS_EXTERN int JS_IsEqual(JSContext *ctx, JSValueConst op1, JSValueConst op2); 465 | JS_EXTERN bool JS_IsStrictEqual(JSContext *ctx, JSValueConst op1, JSValueConst op2); 466 | JS_EXTERN bool JS_IsSameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2); 467 | /* Similar to same-value equality, but +0 and -0 are considered equal. */ 468 | JS_EXTERN bool JS_IsSameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2); 469 | 470 | /* Only used for running 262 tests. TODO(saghul) add build time flag. */ 471 | JS_EXTERN JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, 472 | int argc, JSValueConst *argv); 473 | 474 | JS_EXTERN void *js_calloc_rt(JSRuntime *rt, size_t count, size_t size); 475 | JS_EXTERN void *js_malloc_rt(JSRuntime *rt, size_t size); 476 | JS_EXTERN void js_free_rt(JSRuntime *rt, void *ptr); 477 | JS_EXTERN void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size); 478 | JS_EXTERN size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr); 479 | JS_EXTERN void *js_mallocz_rt(JSRuntime *rt, size_t size); 480 | 481 | JS_EXTERN void *js_calloc(JSContext *ctx, size_t count, size_t size); 482 | JS_EXTERN void *js_malloc(JSContext *ctx, size_t size); 483 | JS_EXTERN void js_free(JSContext *ctx, void *ptr); 484 | JS_EXTERN void *js_realloc(JSContext *ctx, void *ptr, size_t size); 485 | JS_EXTERN size_t js_malloc_usable_size(JSContext *ctx, const void *ptr); 486 | JS_EXTERN void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack); 487 | JS_EXTERN void *js_mallocz(JSContext *ctx, size_t size); 488 | JS_EXTERN char *js_strdup(JSContext *ctx, const char *str); 489 | JS_EXTERN char *js_strndup(JSContext *ctx, const char *s, size_t n); 490 | 491 | typedef struct JSMemoryUsage { 492 | int64_t malloc_size, malloc_limit, memory_used_size; 493 | int64_t malloc_count; 494 | int64_t memory_used_count; 495 | int64_t atom_count, atom_size; 496 | int64_t str_count, str_size; 497 | int64_t obj_count, obj_size; 498 | int64_t prop_count, prop_size; 499 | int64_t shape_count, shape_size; 500 | int64_t js_func_count, js_func_size, js_func_code_size; 501 | int64_t js_func_pc2line_count, js_func_pc2line_size; 502 | int64_t c_func_count, array_count; 503 | int64_t fast_array_count, fast_array_elements; 504 | int64_t binary_object_count, binary_object_size; 505 | } JSMemoryUsage; 506 | 507 | JS_EXTERN void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s); 508 | JS_EXTERN void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); 509 | 510 | /* atom support */ 511 | #define JS_ATOM_NULL 0 512 | 513 | JS_EXTERN JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len); 514 | JS_EXTERN JSAtom JS_NewAtom(JSContext *ctx, const char *str); 515 | JS_EXTERN JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n); 516 | JS_EXTERN JSAtom JS_DupAtom(JSContext *ctx, JSAtom v); 517 | JS_EXTERN void JS_FreeAtom(JSContext *ctx, JSAtom v); 518 | JS_EXTERN void JS_FreeAtomRT(JSRuntime *rt, JSAtom v); 519 | JS_EXTERN JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom); 520 | JS_EXTERN JSValue JS_AtomToString(JSContext *ctx, JSAtom atom); 521 | JS_EXTERN const char *JS_AtomToCString(JSContext *ctx, JSAtom atom); 522 | JS_EXTERN JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val); 523 | 524 | /* object class support */ 525 | 526 | typedef struct JSPropertyEnum { 527 | bool is_enumerable; 528 | JSAtom atom; 529 | } JSPropertyEnum; 530 | 531 | typedef struct JSPropertyDescriptor { 532 | int flags; 533 | JSValue value; 534 | JSValue getter; 535 | JSValue setter; 536 | } JSPropertyDescriptor; 537 | 538 | typedef struct JSClassExoticMethods { 539 | /* Return -1 if exception (can only happen in case of Proxy object), 540 | false if the property does not exists, true if it exists. If 1 is 541 | returned, the property descriptor 'desc' is filled if != NULL. */ 542 | int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc, 543 | JSValueConst obj, JSAtom prop); 544 | /* '*ptab' should hold the '*plen' property keys. Return 0 if OK, 545 | -1 if exception. The 'is_enumerable' field is ignored. 546 | */ 547 | int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab, 548 | uint32_t *plen, JSValueConst obj); 549 | /* return < 0 if exception, or true/false */ 550 | int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop); 551 | /* return < 0 if exception or true/false */ 552 | int (*define_own_property)(JSContext *ctx, JSValueConst this_obj, 553 | JSAtom prop, JSValueConst val, 554 | JSValueConst getter, JSValueConst setter, 555 | int flags); 556 | /* The following methods can be emulated with the previous ones, 557 | so they are usually not needed */ 558 | /* return < 0 if exception or true/false */ 559 | int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom); 560 | JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, 561 | JSValueConst receiver); 562 | /* return < 0 if exception or true/false */ 563 | int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, 564 | JSValueConst value, JSValueConst receiver, int flags); 565 | } JSClassExoticMethods; 566 | 567 | typedef void JSClassFinalizer(JSRuntime *rt, JSValueConst val); 568 | typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val, 569 | JS_MarkFunc *mark_func); 570 | #define JS_CALL_FLAG_CONSTRUCTOR (1 << 0) 571 | typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj, 572 | JSValueConst this_val, int argc, 573 | JSValueConst *argv, int flags); 574 | 575 | typedef struct JSClassDef { 576 | const char *class_name; /* pure ASCII only! */ 577 | JSClassFinalizer *finalizer; 578 | JSClassGCMark *gc_mark; 579 | /* if call != NULL, the object is a function. If (flags & 580 | JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a 581 | constructor. In this case, 'this_val' is new.target. A 582 | constructor call only happens if the object constructor bit is 583 | set (see JS_SetConstructorBit()). */ 584 | JSClassCall *call; 585 | /* XXX: suppress this indirection ? It is here only to save memory 586 | because only a few classes need these methods */ 587 | JSClassExoticMethods *exotic; 588 | } JSClassDef; 589 | 590 | #define JS_EVAL_OPTIONS_VERSION 1 591 | 592 | typedef struct JSEvalOptions { 593 | int version; 594 | int eval_flags; 595 | const char *filename; 596 | int line_num; 597 | // can add new fields in ABI-compatible manner by incrementing JS_EVAL_OPTIONS_VERSION 598 | } JSEvalOptions; 599 | 600 | #define JS_INVALID_CLASS_ID 0 601 | JS_EXTERN JSClassID JS_NewClassID(JSRuntime *rt, JSClassID *pclass_id); 602 | /* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */ 603 | JS_EXTERN JSClassID JS_GetClassID(JSValueConst v); 604 | JS_EXTERN int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); 605 | JS_EXTERN bool JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); 606 | 607 | /* value handling */ 608 | 609 | static js_force_inline JSValue JS_NewBool(JSContext *ctx, bool val) 610 | { 611 | (void)&ctx; 612 | return JS_MKVAL(JS_TAG_BOOL, (val != 0)); 613 | } 614 | 615 | static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val) 616 | { 617 | (void)&ctx; 618 | return JS_MKVAL(JS_TAG_INT, val); 619 | } 620 | 621 | static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double val) 622 | { 623 | (void)&ctx; 624 | return __JS_NewFloat64(val); 625 | } 626 | 627 | static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val) 628 | { 629 | (void)&ctx; 630 | return JS_MKVAL(JS_TAG_CATCH_OFFSET, val); 631 | } 632 | 633 | static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val) 634 | { 635 | JSValue v; 636 | if (val >= INT32_MIN && val <= INT32_MAX) { 637 | v = JS_NewInt32(ctx, (int32_t)val); 638 | } else { 639 | v = JS_NewFloat64(ctx, (double)val); 640 | } 641 | return v; 642 | } 643 | 644 | static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val) 645 | { 646 | JSValue v; 647 | if (val <= INT32_MAX) { 648 | v = JS_NewInt32(ctx, (int32_t)val); 649 | } else { 650 | v = JS_NewFloat64(ctx, (double)val); 651 | } 652 | return v; 653 | } 654 | 655 | JS_EXTERN JSValue JS_NewNumber(JSContext *ctx, double d); 656 | JS_EXTERN JSValue JS_NewBigInt64(JSContext *ctx, int64_t v); 657 | JS_EXTERN JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v); 658 | 659 | static inline bool JS_IsNumber(JSValueConst v) 660 | { 661 | int tag = JS_VALUE_GET_TAG(v); 662 | return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag); 663 | } 664 | 665 | static inline bool JS_IsBigInt(JSContext *ctx, JSValueConst v) 666 | { 667 | (void)&ctx; 668 | return JS_VALUE_GET_TAG(v) == JS_TAG_BIG_INT; 669 | } 670 | 671 | static inline bool JS_IsBool(JSValueConst v) 672 | { 673 | return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL; 674 | } 675 | 676 | static inline bool JS_IsNull(JSValueConst v) 677 | { 678 | return JS_VALUE_GET_TAG(v) == JS_TAG_NULL; 679 | } 680 | 681 | static inline bool JS_IsUndefined(JSValueConst v) 682 | { 683 | return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED; 684 | } 685 | 686 | static inline bool JS_IsException(JSValueConst v) 687 | { 688 | return JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION; 689 | } 690 | 691 | static inline bool JS_IsUninitialized(JSValueConst v) 692 | { 693 | return JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED; 694 | } 695 | 696 | static inline bool JS_IsString(JSValueConst v) 697 | { 698 | return JS_VALUE_GET_TAG(v) == JS_TAG_STRING; 699 | } 700 | 701 | static inline bool JS_IsSymbol(JSValueConst v) 702 | { 703 | return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL; 704 | } 705 | 706 | static inline bool JS_IsObject(JSValueConst v) 707 | { 708 | return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT; 709 | } 710 | 711 | static inline bool JS_IsModule(JSValueConst v) 712 | { 713 | return JS_VALUE_GET_TAG(v) == JS_TAG_MODULE; 714 | } 715 | 716 | JS_EXTERN JSValue JS_Throw(JSContext *ctx, JSValue obj); 717 | JS_EXTERN JSValue JS_GetException(JSContext *ctx); 718 | JS_EXTERN bool JS_HasException(JSContext *ctx); 719 | JS_EXTERN bool JS_IsError(JSContext *ctx, JSValueConst val); 720 | JS_EXTERN bool JS_IsUncatchableError(JSContext* ctx, JSValueConst val); 721 | JS_EXTERN void JS_SetUncatchableError(JSContext *ctx, JSValueConst val); 722 | JS_EXTERN void JS_ClearUncatchableError(JSContext *ctx, JSValueConst val); 723 | // Shorthand for: 724 | // JSValue exc = JS_GetException(ctx); 725 | // JS_ClearUncatchableError(ctx, exc); 726 | // JS_Throw(ctx, exc); 727 | JS_EXTERN void JS_ResetUncatchableError(JSContext *ctx); 728 | JS_EXTERN JSValue JS_NewError(JSContext *ctx); 729 | JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowPlainError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); 730 | JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowSyntaxError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); 731 | JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowTypeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); 732 | JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowReferenceError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); 733 | JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowRangeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); 734 | JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowInternalError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...); 735 | JS_EXTERN JSValue JS_ThrowOutOfMemory(JSContext *ctx); 736 | JS_EXTERN void JS_FreeValue(JSContext *ctx, JSValue v); 737 | JS_EXTERN void JS_FreeValueRT(JSRuntime *rt, JSValue v); 738 | JS_EXTERN JSValue JS_DupValue(JSContext *ctx, JSValueConst v); 739 | JS_EXTERN JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v); 740 | JS_EXTERN int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */ 741 | static inline JSValue JS_ToBoolean(JSContext *ctx, JSValueConst val) 742 | { 743 | return JS_NewBool(ctx, JS_ToBool(ctx, val)); 744 | } 745 | JS_EXTERN JSValue JS_ToNumber(JSContext *ctx, JSValueConst val); 746 | JS_EXTERN int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val); 747 | static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val) 748 | { 749 | return JS_ToInt32(ctx, (int32_t*)pres, val); 750 | } 751 | JS_EXTERN int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val); 752 | JS_EXTERN int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val); 753 | JS_EXTERN int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val); 754 | /* return an exception if 'val' is a Number */ 755 | JS_EXTERN int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val); 756 | JS_EXTERN int JS_ToBigUint64(JSContext *ctx, uint64_t *pres, JSValueConst val); 757 | /* same as JS_ToInt64() but allow BigInt */ 758 | JS_EXTERN int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val); 759 | 760 | JS_EXTERN JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1); 761 | static inline JSValue JS_NewString(JSContext *ctx, const char *str) { 762 | return JS_NewStringLen(ctx, str, strlen(str)); 763 | } 764 | JS_EXTERN JSValue JS_NewAtomString(JSContext *ctx, const char *str); 765 | JS_EXTERN JSValue JS_ToString(JSContext *ctx, JSValueConst val); 766 | JS_EXTERN JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val); 767 | JS_EXTERN const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, bool cesu8); 768 | static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1) 769 | { 770 | return JS_ToCStringLen2(ctx, plen, val1, 0); 771 | } 772 | static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1) 773 | { 774 | return JS_ToCStringLen2(ctx, NULL, val1, 0); 775 | } 776 | JS_EXTERN void JS_FreeCString(JSContext *ctx, const char *ptr); 777 | 778 | JS_EXTERN JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto, 779 | JSClassID class_id); 780 | JS_EXTERN JSValue JS_NewObjectClass(JSContext *ctx, int class_id); 781 | JS_EXTERN JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto); 782 | JS_EXTERN JSValue JS_NewObject(JSContext *ctx); 783 | // takes ownership of the values 784 | JS_EXTERN JSValue JS_NewObjectFrom(JSContext *ctx, int count, 785 | const JSAtom *props, 786 | const JSValue *values); 787 | // takes ownership of the values 788 | JS_EXTERN JSValue JS_NewObjectFromStr(JSContext *ctx, int count, 789 | const char **props, 790 | const JSValue *values); 791 | JS_EXTERN JSValue JS_ToObject(JSContext *ctx, JSValueConst val); 792 | JS_EXTERN JSValue JS_ToObjectString(JSContext *ctx, JSValueConst val); 793 | 794 | JS_EXTERN bool JS_IsFunction(JSContext* ctx, JSValueConst val); 795 | JS_EXTERN bool JS_IsConstructor(JSContext* ctx, JSValueConst val); 796 | JS_EXTERN bool JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, bool val); 797 | 798 | JS_EXTERN bool JS_IsRegExp(JSValueConst val); 799 | JS_EXTERN bool JS_IsMap(JSValueConst val); 800 | 801 | JS_EXTERN JSValue JS_NewArray(JSContext *ctx); 802 | // takes ownership of the values 803 | JS_EXTERN JSValue JS_NewArrayFrom(JSContext *ctx, int count, 804 | const JSValue *values); 805 | // reader beware: JS_IsArray used to "punch" through proxies and check 806 | // if the target object is an array but it no longer does; use JS_IsProxy 807 | // and JS_GetProxyTarget instead, and remember that the target itself can 808 | // also be a proxy, ad infinitum 809 | JS_EXTERN bool JS_IsArray(JSValueConst val); 810 | 811 | JS_EXTERN bool JS_IsProxy(JSValueConst val); 812 | JS_EXTERN JSValue JS_GetProxyTarget(JSContext *ctx, JSValueConst proxy); 813 | JS_EXTERN JSValue JS_GetProxyHandler(JSContext *ctx, JSValueConst proxy); 814 | 815 | JS_EXTERN JSValue JS_NewDate(JSContext *ctx, double epoch_ms); 816 | JS_EXTERN bool JS_IsDate(JSValueConst v); 817 | 818 | JS_EXTERN JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop); 819 | JS_EXTERN JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, 820 | uint32_t idx); 821 | JS_EXTERN JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst this_obj, 822 | int64_t idx); 823 | JS_EXTERN JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, 824 | const char *prop); 825 | 826 | JS_EXTERN int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, 827 | JSAtom prop, JSValue val); 828 | JS_EXTERN int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, 829 | uint32_t idx, JSValue val); 830 | JS_EXTERN int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, 831 | int64_t idx, JSValue val); 832 | JS_EXTERN int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, 833 | const char *prop, JSValue val); 834 | JS_EXTERN int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop); 835 | JS_EXTERN int JS_IsExtensible(JSContext *ctx, JSValueConst obj); 836 | JS_EXTERN int JS_PreventExtensions(JSContext *ctx, JSValueConst obj); 837 | JS_EXTERN int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags); 838 | JS_EXTERN int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValue proto_val); 839 | JS_EXTERN JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val); 840 | JS_EXTERN int JS_GetLength(JSContext *ctx, JSValueConst obj, int64_t *pres); 841 | JS_EXTERN int JS_SetLength(JSContext *ctx, JSValueConst obj, int64_t len); 842 | JS_EXTERN int JS_SealObject(JSContext *ctx, JSValueConst obj); 843 | JS_EXTERN int JS_FreezeObject(JSContext *ctx, JSValueConst obj); 844 | 845 | #define JS_GPN_STRING_MASK (1 << 0) 846 | #define JS_GPN_SYMBOL_MASK (1 << 1) 847 | #define JS_GPN_PRIVATE_MASK (1 << 2) 848 | /* only include the enumerable properties */ 849 | #define JS_GPN_ENUM_ONLY (1 << 4) 850 | /* set theJSPropertyEnum.is_enumerable field */ 851 | #define JS_GPN_SET_ENUM (1 << 5) 852 | 853 | JS_EXTERN int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, 854 | uint32_t *plen, JSValueConst obj, 855 | int flags); 856 | JS_EXTERN int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, 857 | JSValueConst obj, JSAtom prop); 858 | JS_EXTERN void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, 859 | uint32_t len); 860 | 861 | JS_EXTERN JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, 862 | JSValueConst this_obj, int argc, JSValueConst *argv); 863 | JS_EXTERN JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, 864 | int argc, JSValueConst *argv); 865 | JS_EXTERN JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, 866 | int argc, JSValueConst *argv); 867 | JS_EXTERN JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, 868 | JSValueConst new_target, 869 | int argc, JSValueConst *argv); 870 | /* Try to detect if the input is a module. Returns true if parsing the input 871 | * as a module produces no syntax errors. It's a naive approach that is not 872 | * wholly infallible: non-strict classic scripts may _parse_ okay as a module 873 | * but not _execute_ as one (different runtime semantics.) Use with caution. 874 | * |input| can be either ASCII or UTF-8 encoded source code. 875 | */ 876 | JS_EXTERN bool JS_DetectModule(const char *input, size_t input_len); 877 | /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ 878 | JS_EXTERN JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, 879 | const char *filename, int eval_flags); 880 | JS_EXTERN JSValue JS_Eval2(JSContext *ctx, const char *input, size_t input_len, 881 | JSEvalOptions *options); 882 | JS_EXTERN JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj, 883 | const char *input, size_t input_len, 884 | const char *filename, int eval_flags); 885 | JS_EXTERN JSValue JS_EvalThis2(JSContext *ctx, JSValueConst this_obj, 886 | const char *input, size_t input_len, 887 | JSEvalOptions *options); 888 | JS_EXTERN JSValue JS_GetGlobalObject(JSContext *ctx); 889 | JS_EXTERN int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj); 890 | JS_EXTERN int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, 891 | JSAtom prop, JSValueConst val, 892 | JSValueConst getter, JSValueConst setter, 893 | int flags); 894 | JS_EXTERN int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, 895 | JSAtom prop, JSValue val, int flags); 896 | JS_EXTERN int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, 897 | uint32_t idx, JSValue val, int flags); 898 | JS_EXTERN int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, 899 | const char *prop, JSValue val, int flags); 900 | JS_EXTERN int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, 901 | JSAtom prop, JSValue getter, JSValue setter, 902 | int flags); 903 | /* Only supported for custom classes, returns 0 on success < 0 otherwise. */ 904 | JS_EXTERN int JS_SetOpaque(JSValueConst obj, void *opaque); 905 | JS_EXTERN void *JS_GetOpaque(JSValueConst obj, JSClassID class_id); 906 | JS_EXTERN void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id); 907 | JS_EXTERN void *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id); 908 | 909 | /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ 910 | JS_EXTERN JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, 911 | const char *filename); 912 | JS_EXTERN JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, 913 | JSValueConst replacer, JSValueConst space0); 914 | 915 | typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr); 916 | JS_EXTERN JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, 917 | JSFreeArrayBufferDataFunc *free_func, void *opaque, 918 | bool is_shared); 919 | JS_EXTERN JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); 920 | JS_EXTERN void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj); 921 | JS_EXTERN uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj); 922 | JS_EXTERN bool JS_IsArrayBuffer(JSValueConst obj); 923 | JS_EXTERN uint8_t *JS_GetUint8Array(JSContext *ctx, size_t *psize, JSValueConst obj); 924 | 925 | typedef enum JSTypedArrayEnum { 926 | JS_TYPED_ARRAY_UINT8C = 0, 927 | JS_TYPED_ARRAY_INT8, 928 | JS_TYPED_ARRAY_UINT8, 929 | JS_TYPED_ARRAY_INT16, 930 | JS_TYPED_ARRAY_UINT16, 931 | JS_TYPED_ARRAY_INT32, 932 | JS_TYPED_ARRAY_UINT32, 933 | JS_TYPED_ARRAY_BIG_INT64, 934 | JS_TYPED_ARRAY_BIG_UINT64, 935 | JS_TYPED_ARRAY_FLOAT16, 936 | JS_TYPED_ARRAY_FLOAT32, 937 | JS_TYPED_ARRAY_FLOAT64, 938 | } JSTypedArrayEnum; 939 | 940 | JS_EXTERN JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv, 941 | JSTypedArrayEnum array_type); 942 | JS_EXTERN JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, 943 | size_t *pbyte_offset, 944 | size_t *pbyte_length, 945 | size_t *pbytes_per_element); 946 | JS_EXTERN JSValue JS_NewUint8Array(JSContext *ctx, uint8_t *buf, size_t len, 947 | JSFreeArrayBufferDataFunc *free_func, void *opaque, 948 | bool is_shared); 949 | /* returns -1 if not a typed array otherwise return a JSTypedArrayEnum value */ 950 | JS_EXTERN int JS_GetTypedArrayType(JSValueConst obj); 951 | JS_EXTERN JSValue JS_NewUint8ArrayCopy(JSContext *ctx, const uint8_t *buf, size_t len); 952 | typedef struct { 953 | void *(*sab_alloc)(void *opaque, size_t size); 954 | void (*sab_free)(void *opaque, void *ptr); 955 | void (*sab_dup)(void *opaque, void *ptr); 956 | void *sab_opaque; 957 | } JSSharedArrayBufferFunctions; 958 | JS_EXTERN void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf); 959 | 960 | typedef enum JSPromiseStateEnum { 961 | JS_PROMISE_PENDING, 962 | JS_PROMISE_FULFILLED, 963 | JS_PROMISE_REJECTED, 964 | } JSPromiseStateEnum; 965 | 966 | JS_EXTERN JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); 967 | JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx, 968 | JSValueConst promise); 969 | JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValueConst promise); 970 | JS_EXTERN bool JS_IsPromise(JSValueConst val); 971 | 972 | JS_EXTERN JSValue JS_NewSymbol(JSContext *ctx, const char *description, bool is_global); 973 | 974 | /* is_handled = true means that the rejection is handled */ 975 | typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise, 976 | JSValueConst reason, 977 | bool is_handled, void *opaque); 978 | JS_EXTERN void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); 979 | 980 | /* return != 0 if the JS code needs to be interrupted */ 981 | typedef int JSInterruptHandler(JSRuntime *rt, void *opaque); 982 | JS_EXTERN void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque); 983 | /* if can_block is true, Atomics.wait() can be used */ 984 | JS_EXTERN void JS_SetCanBlock(JSRuntime *rt, bool can_block); 985 | /* set the [IsHTMLDDA] internal slot */ 986 | JS_EXTERN void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj); 987 | 988 | typedef struct JSModuleDef JSModuleDef; 989 | 990 | /* return the module specifier (allocated with js_malloc()) or NULL if 991 | exception */ 992 | typedef char *JSModuleNormalizeFunc(JSContext *ctx, 993 | const char *module_base_name, 994 | const char *module_name, void *opaque); 995 | typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx, 996 | const char *module_name, void *opaque); 997 | 998 | /* module_normalize = NULL is allowed and invokes the default module 999 | filename normalizer */ 1000 | JS_EXTERN void JS_SetModuleLoaderFunc(JSRuntime *rt, 1001 | JSModuleNormalizeFunc *module_normalize, 1002 | JSModuleLoaderFunc *module_loader, void *opaque); 1003 | /* return the import.meta object of a module */ 1004 | JS_EXTERN JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m); 1005 | JS_EXTERN JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m); 1006 | JS_EXTERN JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m); 1007 | 1008 | /* JS Job support */ 1009 | 1010 | typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv); 1011 | JS_EXTERN int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, 1012 | int argc, JSValueConst *argv); 1013 | 1014 | JS_EXTERN bool JS_IsJobPending(JSRuntime *rt); 1015 | JS_EXTERN int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); 1016 | 1017 | /* Structure to retrieve (de)serialized SharedArrayBuffer objects. */ 1018 | typedef struct JSSABTab { 1019 | uint8_t **tab; 1020 | size_t len; 1021 | } JSSABTab; 1022 | 1023 | /* Object Writer/Reader (currently only used to handle precompiled code) */ 1024 | #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ 1025 | #define JS_WRITE_OBJ_BSWAP (0) /* byte swapped output (obsolete, handled transparently) */ 1026 | #define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ 1027 | #define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to encode arbitrary object graph */ 1028 | #define JS_WRITE_OBJ_STRIP_SOURCE (1 << 4) /* do not write source code information */ 1029 | #define JS_WRITE_OBJ_STRIP_DEBUG (1 << 5) /* do not write debug information */ 1030 | JS_EXTERN uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, int flags); 1031 | JS_EXTERN uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, 1032 | int flags, JSSABTab *psab_tab); 1033 | 1034 | #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */ 1035 | #define JS_READ_OBJ_ROM_DATA (0) /* avoid duplicating 'buf' data (obsolete, broken by ICs) */ 1036 | #define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ 1037 | #define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */ 1038 | JS_EXTERN JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, int flags); 1039 | JS_EXTERN JSValue JS_ReadObject2(JSContext *ctx, const uint8_t *buf, size_t buf_len, 1040 | int flags, JSSABTab *psab_tab); 1041 | /* instantiate and evaluate a bytecode function. Only used when 1042 | reading a script or module with JS_ReadObject() */ 1043 | JS_EXTERN JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj); 1044 | /* load the dependencies of the module 'obj'. Useful when JS_ReadObject() 1045 | returns a module. */ 1046 | JS_EXTERN int JS_ResolveModule(JSContext *ctx, JSValueConst obj); 1047 | 1048 | /* only exported for os.Worker() */ 1049 | JS_EXTERN JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); 1050 | /* only exported for os.Worker() */ 1051 | JS_EXTERN JSValue JS_LoadModule(JSContext *ctx, const char *basename, 1052 | const char *filename); 1053 | 1054 | /* C function definition */ 1055 | typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ 1056 | JS_CFUNC_generic, 1057 | JS_CFUNC_generic_magic, 1058 | JS_CFUNC_constructor, 1059 | JS_CFUNC_constructor_magic, 1060 | JS_CFUNC_constructor_or_func, 1061 | JS_CFUNC_constructor_or_func_magic, 1062 | JS_CFUNC_f_f, 1063 | JS_CFUNC_f_f_f, 1064 | JS_CFUNC_getter, 1065 | JS_CFUNC_setter, 1066 | JS_CFUNC_getter_magic, 1067 | JS_CFUNC_setter_magic, 1068 | JS_CFUNC_iterator_next, 1069 | } JSCFunctionEnum; 1070 | 1071 | typedef union JSCFunctionType { 1072 | JSCFunction *generic; 1073 | JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); 1074 | JSCFunction *constructor; 1075 | JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic); 1076 | JSCFunction *constructor_or_func; 1077 | double (*f_f)(double); 1078 | double (*f_f_f)(double, double); 1079 | JSValue (*getter)(JSContext *ctx, JSValueConst this_val); 1080 | JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val); 1081 | JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic); 1082 | JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic); 1083 | JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val, 1084 | int argc, JSValueConst *argv, int *pdone, int magic); 1085 | } JSCFunctionType; 1086 | 1087 | JS_EXTERN JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, 1088 | const char *name, 1089 | int length, JSCFunctionEnum cproto, int magic); 1090 | JS_EXTERN JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func, 1091 | const char *name, 1092 | int length, JSCFunctionEnum cproto, int magic, 1093 | JSValue proto_val); 1094 | JS_EXTERN JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, 1095 | int length, int magic, int data_len, 1096 | JSValueConst *data); 1097 | 1098 | static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, 1099 | const char *name, int length) 1100 | { 1101 | return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0); 1102 | } 1103 | 1104 | static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func, 1105 | const char *name, int length, 1106 | JSCFunctionEnum cproto, int magic) 1107 | { 1108 | /* Used to squelch a -Wcast-function-type warning. */ 1109 | JSCFunctionType ft; 1110 | ft.generic_magic = func; 1111 | return JS_NewCFunction2(ctx, ft.generic, name, length, cproto, magic); 1112 | } 1113 | JS_EXTERN void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, 1114 | JSValueConst proto); 1115 | 1116 | /* C property definition */ 1117 | 1118 | typedef struct JSCFunctionListEntry { 1119 | const char *name; /* pure ASCII or UTF-8 encoded */ 1120 | uint8_t prop_flags; 1121 | uint8_t def_type; 1122 | int16_t magic; 1123 | union { 1124 | struct { 1125 | uint8_t length; /* XXX: should move outside union */ 1126 | uint8_t cproto; /* XXX: should move outside union */ 1127 | JSCFunctionType cfunc; 1128 | } func; 1129 | struct { 1130 | JSCFunctionType get; 1131 | JSCFunctionType set; 1132 | } getset; 1133 | struct { 1134 | const char *name; 1135 | int base; 1136 | } alias; 1137 | struct { 1138 | const struct JSCFunctionListEntry *tab; 1139 | int len; 1140 | } prop_list; 1141 | const char *str; /* pure ASCII or UTF-8 encoded */ 1142 | int32_t i32; 1143 | int64_t i64; 1144 | uint64_t u64; 1145 | double f64; 1146 | } u; 1147 | } JSCFunctionListEntry; 1148 | 1149 | #define JS_DEF_CFUNC 0 1150 | #define JS_DEF_CGETSET 1 1151 | #define JS_DEF_CGETSET_MAGIC 2 1152 | #define JS_DEF_PROP_STRING 3 1153 | #define JS_DEF_PROP_INT32 4 1154 | #define JS_DEF_PROP_INT64 5 1155 | #define JS_DEF_PROP_DOUBLE 6 1156 | #define JS_DEF_PROP_UNDEFINED 7 1157 | #define JS_DEF_OBJECT 8 1158 | #define JS_DEF_ALIAS 9 1159 | 1160 | /* Note: c++ does not like nested designators */ 1161 | #define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } 1162 | #define JS_CFUNC_DEF2(name, length, func1, prop_flags) { name, prop_flags, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } 1163 | #define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } } 1164 | #define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } } 1165 | #define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } } 1166 | #define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } 1167 | #define JS_CGETSET_DEF2(name, fgetter, fsetter, prop_flags) { name, prop_flags, JS_DEF_CGETSET, 0, { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } 1168 | #define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } } 1169 | #define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, { .str = cstr } } 1170 | #define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, { .i32 = val } } 1171 | #define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, { .i64 = val } } 1172 | #define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, { .f64 = val } } 1173 | #define JS_PROP_U2D_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, { .u64 = val } } 1174 | #define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, { .i32 = 0 } } 1175 | #define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, { .prop_list = { tab, len } } } 1176 | #define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, -1 } } } 1177 | #define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, base } } } 1178 | 1179 | JS_EXTERN void JS_SetPropertyFunctionList(JSContext *ctx, JSValue obj, 1180 | const JSCFunctionListEntry *tab, 1181 | int len); 1182 | 1183 | /* C module definition */ 1184 | 1185 | typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m); 1186 | 1187 | JS_EXTERN JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, 1188 | JSModuleInitFunc *func); 1189 | /* can only be called before the module is instantiated */ 1190 | JS_EXTERN int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str); 1191 | JS_EXTERN int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m, 1192 | const JSCFunctionListEntry *tab, int len); 1193 | /* can only be called after the module is instantiated */ 1194 | JS_EXTERN int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, 1195 | JSValue val); 1196 | JS_EXTERN int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, 1197 | const JSCFunctionListEntry *tab, int len); 1198 | 1199 | /* Version */ 1200 | 1201 | #define QJS_VERSION_MAJOR 0 1202 | #define QJS_VERSION_MINOR 9 1203 | #define QJS_VERSION_PATCH 0 1204 | #define QJS_VERSION_SUFFIX "" 1205 | 1206 | JS_EXTERN const char* JS_GetVersion(void); 1207 | 1208 | /* Integration point for quickjs-libc.c, not for public use. */ 1209 | JS_EXTERN uintptr_t js_std_cmd(int cmd, ...); 1210 | 1211 | #undef JS_EXTERN 1212 | #undef js_force_inline 1213 | 1214 | #ifdef __cplusplus 1215 | } /* extern "C" { */ 1216 | #endif 1217 | 1218 | #endif /* QUICKJS_H */ 1219 | -------------------------------------------------------------------------------- /libs/sqlite3ext.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** 2006 June 7 3 | ** 4 | ** The author disclaims copyright to this source code. In place of 5 | ** a legal notice, here is a blessing: 6 | ** 7 | ** May you do good and not evil. 8 | ** May you find forgiveness for yourself and forgive others. 9 | ** May you share freely, never taking more than you give. 10 | ** 11 | ************************************************************************* 12 | ** This header file defines the SQLite interface for use by 13 | ** shared libraries that want to be imported as extensions into 14 | ** an SQLite instance. Shared libraries that intend to be loaded 15 | ** as extensions by SQLite should #include this file instead of 16 | ** sqlite3.h. 17 | */ 18 | #ifndef SQLITE3EXT_H 19 | #define SQLITE3EXT_H 20 | #include "sqlite3.h" 21 | 22 | /* 23 | ** The following structure holds pointers to all of the SQLite API 24 | ** routines. 25 | ** 26 | ** WARNING: In order to maintain backwards compatibility, add new 27 | ** interfaces to the end of this structure only. If you insert new 28 | ** interfaces in the middle of this structure, then older different 29 | ** versions of SQLite will not be able to load each other's shared 30 | ** libraries! 31 | */ 32 | struct sqlite3_api_routines { 33 | void * (*aggregate_context)(sqlite3_context*,int nBytes); 34 | int (*aggregate_count)(sqlite3_context*); 35 | int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); 36 | int (*bind_double)(sqlite3_stmt*,int,double); 37 | int (*bind_int)(sqlite3_stmt*,int,int); 38 | int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); 39 | int (*bind_null)(sqlite3_stmt*,int); 40 | int (*bind_parameter_count)(sqlite3_stmt*); 41 | int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); 42 | const char * (*bind_parameter_name)(sqlite3_stmt*,int); 43 | int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); 44 | int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); 45 | int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); 46 | int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); 47 | int (*busy_timeout)(sqlite3*,int ms); 48 | int (*changes)(sqlite3*); 49 | int (*close)(sqlite3*); 50 | int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, 51 | int eTextRep,const char*)); 52 | int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, 53 | int eTextRep,const void*)); 54 | const void * (*column_blob)(sqlite3_stmt*,int iCol); 55 | int (*column_bytes)(sqlite3_stmt*,int iCol); 56 | int (*column_bytes16)(sqlite3_stmt*,int iCol); 57 | int (*column_count)(sqlite3_stmt*pStmt); 58 | const char * (*column_database_name)(sqlite3_stmt*,int); 59 | const void * (*column_database_name16)(sqlite3_stmt*,int); 60 | const char * (*column_decltype)(sqlite3_stmt*,int i); 61 | const void * (*column_decltype16)(sqlite3_stmt*,int); 62 | double (*column_double)(sqlite3_stmt*,int iCol); 63 | int (*column_int)(sqlite3_stmt*,int iCol); 64 | sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); 65 | const char * (*column_name)(sqlite3_stmt*,int); 66 | const void * (*column_name16)(sqlite3_stmt*,int); 67 | const char * (*column_origin_name)(sqlite3_stmt*,int); 68 | const void * (*column_origin_name16)(sqlite3_stmt*,int); 69 | const char * (*column_table_name)(sqlite3_stmt*,int); 70 | const void * (*column_table_name16)(sqlite3_stmt*,int); 71 | const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); 72 | const void * (*column_text16)(sqlite3_stmt*,int iCol); 73 | int (*column_type)(sqlite3_stmt*,int iCol); 74 | sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); 75 | void * (*commit_hook)(sqlite3*,int(*)(void*),void*); 76 | int (*complete)(const char*sql); 77 | int (*complete16)(const void*sql); 78 | int (*create_collation)(sqlite3*,const char*,int,void*, 79 | int(*)(void*,int,const void*,int,const void*)); 80 | int (*create_collation16)(sqlite3*,const void*,int,void*, 81 | int(*)(void*,int,const void*,int,const void*)); 82 | int (*create_function)(sqlite3*,const char*,int,int,void*, 83 | void (*xFunc)(sqlite3_context*,int,sqlite3_value**), 84 | void (*xStep)(sqlite3_context*,int,sqlite3_value**), 85 | void (*xFinal)(sqlite3_context*)); 86 | int (*create_function16)(sqlite3*,const void*,int,int,void*, 87 | void (*xFunc)(sqlite3_context*,int,sqlite3_value**), 88 | void (*xStep)(sqlite3_context*,int,sqlite3_value**), 89 | void (*xFinal)(sqlite3_context*)); 90 | int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); 91 | int (*data_count)(sqlite3_stmt*pStmt); 92 | sqlite3 * (*db_handle)(sqlite3_stmt*); 93 | int (*declare_vtab)(sqlite3*,const char*); 94 | int (*enable_shared_cache)(int); 95 | int (*errcode)(sqlite3*db); 96 | const char * (*errmsg)(sqlite3*); 97 | const void * (*errmsg16)(sqlite3*); 98 | int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); 99 | int (*expired)(sqlite3_stmt*); 100 | int (*finalize)(sqlite3_stmt*pStmt); 101 | void (*free)(void*); 102 | void (*free_table)(char**result); 103 | int (*get_autocommit)(sqlite3*); 104 | void * (*get_auxdata)(sqlite3_context*,int); 105 | int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); 106 | int (*global_recover)(void); 107 | void (*interruptx)(sqlite3*); 108 | sqlite_int64 (*last_insert_rowid)(sqlite3*); 109 | const char * (*libversion)(void); 110 | int (*libversion_number)(void); 111 | void *(*malloc)(int); 112 | char * (*mprintf)(const char*,...); 113 | int (*open)(const char*,sqlite3**); 114 | int (*open16)(const void*,sqlite3**); 115 | int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); 116 | int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); 117 | void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); 118 | void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); 119 | void *(*realloc)(void*,int); 120 | int (*reset)(sqlite3_stmt*pStmt); 121 | void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); 122 | void (*result_double)(sqlite3_context*,double); 123 | void (*result_error)(sqlite3_context*,const char*,int); 124 | void (*result_error16)(sqlite3_context*,const void*,int); 125 | void (*result_int)(sqlite3_context*,int); 126 | void (*result_int64)(sqlite3_context*,sqlite_int64); 127 | void (*result_null)(sqlite3_context*); 128 | void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); 129 | void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); 130 | void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); 131 | void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); 132 | void (*result_value)(sqlite3_context*,sqlite3_value*); 133 | void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); 134 | int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, 135 | const char*,const char*),void*); 136 | void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); 137 | char * (*xsnprintf)(int,char*,const char*,...); 138 | int (*step)(sqlite3_stmt*); 139 | int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, 140 | char const**,char const**,int*,int*,int*); 141 | void (*thread_cleanup)(void); 142 | int (*total_changes)(sqlite3*); 143 | void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); 144 | int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); 145 | void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, 146 | sqlite_int64),void*); 147 | void * (*user_data)(sqlite3_context*); 148 | const void * (*value_blob)(sqlite3_value*); 149 | int (*value_bytes)(sqlite3_value*); 150 | int (*value_bytes16)(sqlite3_value*); 151 | double (*value_double)(sqlite3_value*); 152 | int (*value_int)(sqlite3_value*); 153 | sqlite_int64 (*value_int64)(sqlite3_value*); 154 | int (*value_numeric_type)(sqlite3_value*); 155 | const unsigned char * (*value_text)(sqlite3_value*); 156 | const void * (*value_text16)(sqlite3_value*); 157 | const void * (*value_text16be)(sqlite3_value*); 158 | const void * (*value_text16le)(sqlite3_value*); 159 | int (*value_type)(sqlite3_value*); 160 | char *(*vmprintf)(const char*,va_list); 161 | /* Added ??? */ 162 | int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); 163 | /* Added by 3.3.13 */ 164 | int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); 165 | int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); 166 | int (*clear_bindings)(sqlite3_stmt*); 167 | /* Added by 3.4.1 */ 168 | int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, 169 | void (*xDestroy)(void *)); 170 | /* Added by 3.5.0 */ 171 | int (*bind_zeroblob)(sqlite3_stmt*,int,int); 172 | int (*blob_bytes)(sqlite3_blob*); 173 | int (*blob_close)(sqlite3_blob*); 174 | int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, 175 | int,sqlite3_blob**); 176 | int (*blob_read)(sqlite3_blob*,void*,int,int); 177 | int (*blob_write)(sqlite3_blob*,const void*,int,int); 178 | int (*create_collation_v2)(sqlite3*,const char*,int,void*, 179 | int(*)(void*,int,const void*,int,const void*), 180 | void(*)(void*)); 181 | int (*file_control)(sqlite3*,const char*,int,void*); 182 | sqlite3_int64 (*memory_highwater)(int); 183 | sqlite3_int64 (*memory_used)(void); 184 | sqlite3_mutex *(*mutex_alloc)(int); 185 | void (*mutex_enter)(sqlite3_mutex*); 186 | void (*mutex_free)(sqlite3_mutex*); 187 | void (*mutex_leave)(sqlite3_mutex*); 188 | int (*mutex_try)(sqlite3_mutex*); 189 | int (*open_v2)(const char*,sqlite3**,int,const char*); 190 | int (*release_memory)(int); 191 | void (*result_error_nomem)(sqlite3_context*); 192 | void (*result_error_toobig)(sqlite3_context*); 193 | int (*sleep)(int); 194 | void (*soft_heap_limit)(int); 195 | sqlite3_vfs *(*vfs_find)(const char*); 196 | int (*vfs_register)(sqlite3_vfs*,int); 197 | int (*vfs_unregister)(sqlite3_vfs*); 198 | int (*xthreadsafe)(void); 199 | void (*result_zeroblob)(sqlite3_context*,int); 200 | void (*result_error_code)(sqlite3_context*,int); 201 | int (*test_control)(int, ...); 202 | void (*randomness)(int,void*); 203 | sqlite3 *(*context_db_handle)(sqlite3_context*); 204 | int (*extended_result_codes)(sqlite3*,int); 205 | int (*limit)(sqlite3*,int,int); 206 | sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*); 207 | const char *(*sql)(sqlite3_stmt*); 208 | int (*status)(int,int*,int*,int); 209 | int (*backup_finish)(sqlite3_backup*); 210 | sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*); 211 | int (*backup_pagecount)(sqlite3_backup*); 212 | int (*backup_remaining)(sqlite3_backup*); 213 | int (*backup_step)(sqlite3_backup*,int); 214 | const char *(*compileoption_get)(int); 215 | int (*compileoption_used)(const char*); 216 | int (*create_function_v2)(sqlite3*,const char*,int,int,void*, 217 | void (*xFunc)(sqlite3_context*,int,sqlite3_value**), 218 | void (*xStep)(sqlite3_context*,int,sqlite3_value**), 219 | void (*xFinal)(sqlite3_context*), 220 | void(*xDestroy)(void*)); 221 | int (*db_config)(sqlite3*,int,...); 222 | sqlite3_mutex *(*db_mutex)(sqlite3*); 223 | int (*db_status)(sqlite3*,int,int*,int*,int); 224 | int (*extended_errcode)(sqlite3*); 225 | void (*log)(int,const char*,...); 226 | sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); 227 | const char *(*sourceid)(void); 228 | int (*stmt_status)(sqlite3_stmt*,int,int); 229 | int (*strnicmp)(const char*,const char*,int); 230 | int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); 231 | int (*wal_autocheckpoint)(sqlite3*,int); 232 | int (*wal_checkpoint)(sqlite3*,const char*); 233 | void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); 234 | int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); 235 | int (*vtab_config)(sqlite3*,int op,...); 236 | int (*vtab_on_conflict)(sqlite3*); 237 | /* Version 3.7.16 and later */ 238 | int (*close_v2)(sqlite3*); 239 | const char *(*db_filename)(sqlite3*,const char*); 240 | int (*db_readonly)(sqlite3*,const char*); 241 | int (*db_release_memory)(sqlite3*); 242 | const char *(*errstr)(int); 243 | int (*stmt_busy)(sqlite3_stmt*); 244 | int (*stmt_readonly)(sqlite3_stmt*); 245 | int (*stricmp)(const char*,const char*); 246 | int (*uri_boolean)(const char*,const char*,int); 247 | sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); 248 | const char *(*uri_parameter)(const char*,const char*); 249 | char *(*xvsnprintf)(int,char*,const char*,va_list); 250 | int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); 251 | /* Version 3.8.7 and later */ 252 | int (*auto_extension)(void(*)(void)); 253 | int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, 254 | void(*)(void*)); 255 | int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, 256 | void(*)(void*),unsigned char); 257 | int (*cancel_auto_extension)(void(*)(void)); 258 | int (*load_extension)(sqlite3*,const char*,const char*,char**); 259 | void *(*malloc64)(sqlite3_uint64); 260 | sqlite3_uint64 (*msize)(void*); 261 | void *(*realloc64)(void*,sqlite3_uint64); 262 | void (*reset_auto_extension)(void); 263 | void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, 264 | void(*)(void*)); 265 | void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, 266 | void(*)(void*), unsigned char); 267 | int (*strglob)(const char*,const char*); 268 | /* Version 3.8.11 and later */ 269 | sqlite3_value *(*value_dup)(const sqlite3_value*); 270 | void (*value_free)(sqlite3_value*); 271 | int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64); 272 | int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64); 273 | /* Version 3.9.0 and later */ 274 | unsigned int (*value_subtype)(sqlite3_value*); 275 | void (*result_subtype)(sqlite3_context*,unsigned int); 276 | /* Version 3.10.0 and later */ 277 | int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); 278 | int (*strlike)(const char*,const char*,unsigned int); 279 | int (*db_cacheflush)(sqlite3*); 280 | /* Version 3.12.0 and later */ 281 | int (*system_errno)(sqlite3*); 282 | /* Version 3.14.0 and later */ 283 | int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); 284 | char *(*expanded_sql)(sqlite3_stmt*); 285 | /* Version 3.18.0 and later */ 286 | void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); 287 | /* Version 3.20.0 and later */ 288 | int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, 289 | sqlite3_stmt**,const char**); 290 | int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, 291 | sqlite3_stmt**,const void**); 292 | int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); 293 | void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); 294 | void *(*value_pointer)(sqlite3_value*,const char*); 295 | int (*vtab_nochange)(sqlite3_context*); 296 | int (*value_nochange)(sqlite3_value*); 297 | const char *(*vtab_collation)(sqlite3_index_info*,int); 298 | /* Version 3.24.0 and later */ 299 | int (*keyword_count)(void); 300 | int (*keyword_name)(int,const char**,int*); 301 | int (*keyword_check)(const char*,int); 302 | sqlite3_str *(*str_new)(sqlite3*); 303 | char *(*str_finish)(sqlite3_str*); 304 | void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); 305 | void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); 306 | void (*str_append)(sqlite3_str*, const char *zIn, int N); 307 | void (*str_appendall)(sqlite3_str*, const char *zIn); 308 | void (*str_appendchar)(sqlite3_str*, int N, char C); 309 | void (*str_reset)(sqlite3_str*); 310 | int (*str_errcode)(sqlite3_str*); 311 | int (*str_length)(sqlite3_str*); 312 | char *(*str_value)(sqlite3_str*); 313 | /* Version 3.25.0 and later */ 314 | int (*create_window_function)(sqlite3*,const char*,int,int,void*, 315 | void (*xStep)(sqlite3_context*,int,sqlite3_value**), 316 | void (*xFinal)(sqlite3_context*), 317 | void (*xValue)(sqlite3_context*), 318 | void (*xInv)(sqlite3_context*,int,sqlite3_value**), 319 | void(*xDestroy)(void*)); 320 | /* Version 3.26.0 and later */ 321 | const char *(*normalized_sql)(sqlite3_stmt*); 322 | /* Version 3.28.0 and later */ 323 | int (*stmt_isexplain)(sqlite3_stmt*); 324 | int (*value_frombind)(sqlite3_value*); 325 | /* Version 3.30.0 and later */ 326 | int (*drop_modules)(sqlite3*,const char**); 327 | /* Version 3.31.0 and later */ 328 | sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64); 329 | const char *(*uri_key)(const char*,int); 330 | const char *(*filename_database)(const char*); 331 | const char *(*filename_journal)(const char*); 332 | const char *(*filename_wal)(const char*); 333 | /* Version 3.32.0 and later */ 334 | const char *(*create_filename)(const char*,const char*,const char*, 335 | int,const char**); 336 | void (*free_filename)(const char*); 337 | sqlite3_file *(*database_file_object)(const char*); 338 | /* Version 3.34.0 and later */ 339 | int (*txn_state)(sqlite3*,const char*); 340 | /* Version 3.36.1 and later */ 341 | sqlite3_int64 (*changes64)(sqlite3*); 342 | sqlite3_int64 (*total_changes64)(sqlite3*); 343 | /* Version 3.37.0 and later */ 344 | int (*autovacuum_pages)(sqlite3*, 345 | unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), 346 | void*, void(*)(void*)); 347 | /* Version 3.38.0 and later */ 348 | int (*error_offset)(sqlite3*); 349 | int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**); 350 | int (*vtab_distinct)(sqlite3_index_info*); 351 | int (*vtab_in)(sqlite3_index_info*,int,int); 352 | int (*vtab_in_first)(sqlite3_value*,sqlite3_value**); 353 | int (*vtab_in_next)(sqlite3_value*,sqlite3_value**); 354 | /* Version 3.39.0 and later */ 355 | int (*deserialize)(sqlite3*,const char*,unsigned char*, 356 | sqlite3_int64,sqlite3_int64,unsigned); 357 | unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*, 358 | unsigned int); 359 | const char *(*db_name)(sqlite3*,int); 360 | /* Version 3.40.0 and later */ 361 | int (*value_encoding)(sqlite3_value*); 362 | /* Version 3.41.0 and later */ 363 | int (*is_interrupted)(sqlite3*); 364 | /* Version 3.43.0 and later */ 365 | int (*stmt_explain)(sqlite3_stmt*,int); 366 | /* Version 3.44.0 and later */ 367 | void *(*get_clientdata)(sqlite3*,const char*); 368 | int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); 369 | }; 370 | 371 | /* 372 | ** This is the function signature used for all extension entry points. It 373 | ** is also defined in the file "loadext.c". 374 | */ 375 | typedef int (*sqlite3_loadext_entry)( 376 | sqlite3 *db, /* Handle to the database. */ 377 | char **pzErrMsg, /* Used to set error string on failure. */ 378 | const sqlite3_api_routines *pThunk /* Extension API function pointers. */ 379 | ); 380 | 381 | /* 382 | ** The following macros redefine the API routines so that they are 383 | ** redirected through the global sqlite3_api structure. 384 | ** 385 | ** This header file is also used by the loadext.c source file 386 | ** (part of the main SQLite library - not an extension) so that 387 | ** it can get access to the sqlite3_api_routines structure 388 | ** definition. But the main library does not want to redefine 389 | ** the API. So the redefinition macros are only valid if the 390 | ** SQLITE_CORE macros is undefined. 391 | */ 392 | #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) 393 | #define sqlite3_aggregate_context sqlite3_api->aggregate_context 394 | #ifndef SQLITE_OMIT_DEPRECATED 395 | #define sqlite3_aggregate_count sqlite3_api->aggregate_count 396 | #endif 397 | #define sqlite3_bind_blob sqlite3_api->bind_blob 398 | #define sqlite3_bind_double sqlite3_api->bind_double 399 | #define sqlite3_bind_int sqlite3_api->bind_int 400 | #define sqlite3_bind_int64 sqlite3_api->bind_int64 401 | #define sqlite3_bind_null sqlite3_api->bind_null 402 | #define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count 403 | #define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index 404 | #define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name 405 | #define sqlite3_bind_text sqlite3_api->bind_text 406 | #define sqlite3_bind_text16 sqlite3_api->bind_text16 407 | #define sqlite3_bind_value sqlite3_api->bind_value 408 | #define sqlite3_busy_handler sqlite3_api->busy_handler 409 | #define sqlite3_busy_timeout sqlite3_api->busy_timeout 410 | #define sqlite3_changes sqlite3_api->changes 411 | #define sqlite3_close sqlite3_api->close 412 | #define sqlite3_collation_needed sqlite3_api->collation_needed 413 | #define sqlite3_collation_needed16 sqlite3_api->collation_needed16 414 | #define sqlite3_column_blob sqlite3_api->column_blob 415 | #define sqlite3_column_bytes sqlite3_api->column_bytes 416 | #define sqlite3_column_bytes16 sqlite3_api->column_bytes16 417 | #define sqlite3_column_count sqlite3_api->column_count 418 | #define sqlite3_column_database_name sqlite3_api->column_database_name 419 | #define sqlite3_column_database_name16 sqlite3_api->column_database_name16 420 | #define sqlite3_column_decltype sqlite3_api->column_decltype 421 | #define sqlite3_column_decltype16 sqlite3_api->column_decltype16 422 | #define sqlite3_column_double sqlite3_api->column_double 423 | #define sqlite3_column_int sqlite3_api->column_int 424 | #define sqlite3_column_int64 sqlite3_api->column_int64 425 | #define sqlite3_column_name sqlite3_api->column_name 426 | #define sqlite3_column_name16 sqlite3_api->column_name16 427 | #define sqlite3_column_origin_name sqlite3_api->column_origin_name 428 | #define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16 429 | #define sqlite3_column_table_name sqlite3_api->column_table_name 430 | #define sqlite3_column_table_name16 sqlite3_api->column_table_name16 431 | #define sqlite3_column_text sqlite3_api->column_text 432 | #define sqlite3_column_text16 sqlite3_api->column_text16 433 | #define sqlite3_column_type sqlite3_api->column_type 434 | #define sqlite3_column_value sqlite3_api->column_value 435 | #define sqlite3_commit_hook sqlite3_api->commit_hook 436 | #define sqlite3_complete sqlite3_api->complete 437 | #define sqlite3_complete16 sqlite3_api->complete16 438 | #define sqlite3_create_collation sqlite3_api->create_collation 439 | #define sqlite3_create_collation16 sqlite3_api->create_collation16 440 | #define sqlite3_create_function sqlite3_api->create_function 441 | #define sqlite3_create_function16 sqlite3_api->create_function16 442 | #define sqlite3_create_module sqlite3_api->create_module 443 | #define sqlite3_create_module_v2 sqlite3_api->create_module_v2 444 | #define sqlite3_data_count sqlite3_api->data_count 445 | #define sqlite3_db_handle sqlite3_api->db_handle 446 | #define sqlite3_declare_vtab sqlite3_api->declare_vtab 447 | #define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache 448 | #define sqlite3_errcode sqlite3_api->errcode 449 | #define sqlite3_errmsg sqlite3_api->errmsg 450 | #define sqlite3_errmsg16 sqlite3_api->errmsg16 451 | #define sqlite3_exec sqlite3_api->exec 452 | #ifndef SQLITE_OMIT_DEPRECATED 453 | #define sqlite3_expired sqlite3_api->expired 454 | #endif 455 | #define sqlite3_finalize sqlite3_api->finalize 456 | #define sqlite3_free sqlite3_api->free 457 | #define sqlite3_free_table sqlite3_api->free_table 458 | #define sqlite3_get_autocommit sqlite3_api->get_autocommit 459 | #define sqlite3_get_auxdata sqlite3_api->get_auxdata 460 | #define sqlite3_get_table sqlite3_api->get_table 461 | #ifndef SQLITE_OMIT_DEPRECATED 462 | #define sqlite3_global_recover sqlite3_api->global_recover 463 | #endif 464 | #define sqlite3_interrupt sqlite3_api->interruptx 465 | #define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid 466 | #define sqlite3_libversion sqlite3_api->libversion 467 | #define sqlite3_libversion_number sqlite3_api->libversion_number 468 | #define sqlite3_malloc sqlite3_api->malloc 469 | #define sqlite3_mprintf sqlite3_api->mprintf 470 | #define sqlite3_open sqlite3_api->open 471 | #define sqlite3_open16 sqlite3_api->open16 472 | #define sqlite3_prepare sqlite3_api->prepare 473 | #define sqlite3_prepare16 sqlite3_api->prepare16 474 | #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 475 | #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 476 | #define sqlite3_profile sqlite3_api->profile 477 | #define sqlite3_progress_handler sqlite3_api->progress_handler 478 | #define sqlite3_realloc sqlite3_api->realloc 479 | #define sqlite3_reset sqlite3_api->reset 480 | #define sqlite3_result_blob sqlite3_api->result_blob 481 | #define sqlite3_result_double sqlite3_api->result_double 482 | #define sqlite3_result_error sqlite3_api->result_error 483 | #define sqlite3_result_error16 sqlite3_api->result_error16 484 | #define sqlite3_result_int sqlite3_api->result_int 485 | #define sqlite3_result_int64 sqlite3_api->result_int64 486 | #define sqlite3_result_null sqlite3_api->result_null 487 | #define sqlite3_result_text sqlite3_api->result_text 488 | #define sqlite3_result_text16 sqlite3_api->result_text16 489 | #define sqlite3_result_text16be sqlite3_api->result_text16be 490 | #define sqlite3_result_text16le sqlite3_api->result_text16le 491 | #define sqlite3_result_value sqlite3_api->result_value 492 | #define sqlite3_rollback_hook sqlite3_api->rollback_hook 493 | #define sqlite3_set_authorizer sqlite3_api->set_authorizer 494 | #define sqlite3_set_auxdata sqlite3_api->set_auxdata 495 | #define sqlite3_snprintf sqlite3_api->xsnprintf 496 | #define sqlite3_step sqlite3_api->step 497 | #define sqlite3_table_column_metadata sqlite3_api->table_column_metadata 498 | #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup 499 | #define sqlite3_total_changes sqlite3_api->total_changes 500 | #define sqlite3_trace sqlite3_api->trace 501 | #ifndef SQLITE_OMIT_DEPRECATED 502 | #define sqlite3_transfer_bindings sqlite3_api->transfer_bindings 503 | #endif 504 | #define sqlite3_update_hook sqlite3_api->update_hook 505 | #define sqlite3_user_data sqlite3_api->user_data 506 | #define sqlite3_value_blob sqlite3_api->value_blob 507 | #define sqlite3_value_bytes sqlite3_api->value_bytes 508 | #define sqlite3_value_bytes16 sqlite3_api->value_bytes16 509 | #define sqlite3_value_double sqlite3_api->value_double 510 | #define sqlite3_value_int sqlite3_api->value_int 511 | #define sqlite3_value_int64 sqlite3_api->value_int64 512 | #define sqlite3_value_numeric_type sqlite3_api->value_numeric_type 513 | #define sqlite3_value_text sqlite3_api->value_text 514 | #define sqlite3_value_text16 sqlite3_api->value_text16 515 | #define sqlite3_value_text16be sqlite3_api->value_text16be 516 | #define sqlite3_value_text16le sqlite3_api->value_text16le 517 | #define sqlite3_value_type sqlite3_api->value_type 518 | #define sqlite3_vmprintf sqlite3_api->vmprintf 519 | #define sqlite3_vsnprintf sqlite3_api->xvsnprintf 520 | #define sqlite3_overload_function sqlite3_api->overload_function 521 | #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 522 | #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 523 | #define sqlite3_clear_bindings sqlite3_api->clear_bindings 524 | #define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob 525 | #define sqlite3_blob_bytes sqlite3_api->blob_bytes 526 | #define sqlite3_blob_close sqlite3_api->blob_close 527 | #define sqlite3_blob_open sqlite3_api->blob_open 528 | #define sqlite3_blob_read sqlite3_api->blob_read 529 | #define sqlite3_blob_write sqlite3_api->blob_write 530 | #define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2 531 | #define sqlite3_file_control sqlite3_api->file_control 532 | #define sqlite3_memory_highwater sqlite3_api->memory_highwater 533 | #define sqlite3_memory_used sqlite3_api->memory_used 534 | #define sqlite3_mutex_alloc sqlite3_api->mutex_alloc 535 | #define sqlite3_mutex_enter sqlite3_api->mutex_enter 536 | #define sqlite3_mutex_free sqlite3_api->mutex_free 537 | #define sqlite3_mutex_leave sqlite3_api->mutex_leave 538 | #define sqlite3_mutex_try sqlite3_api->mutex_try 539 | #define sqlite3_open_v2 sqlite3_api->open_v2 540 | #define sqlite3_release_memory sqlite3_api->release_memory 541 | #define sqlite3_result_error_nomem sqlite3_api->result_error_nomem 542 | #define sqlite3_result_error_toobig sqlite3_api->result_error_toobig 543 | #define sqlite3_sleep sqlite3_api->sleep 544 | #define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit 545 | #define sqlite3_vfs_find sqlite3_api->vfs_find 546 | #define sqlite3_vfs_register sqlite3_api->vfs_register 547 | #define sqlite3_vfs_unregister sqlite3_api->vfs_unregister 548 | #define sqlite3_threadsafe sqlite3_api->xthreadsafe 549 | #define sqlite3_result_zeroblob sqlite3_api->result_zeroblob 550 | #define sqlite3_result_error_code sqlite3_api->result_error_code 551 | #define sqlite3_test_control sqlite3_api->test_control 552 | #define sqlite3_randomness sqlite3_api->randomness 553 | #define sqlite3_context_db_handle sqlite3_api->context_db_handle 554 | #define sqlite3_extended_result_codes sqlite3_api->extended_result_codes 555 | #define sqlite3_limit sqlite3_api->limit 556 | #define sqlite3_next_stmt sqlite3_api->next_stmt 557 | #define sqlite3_sql sqlite3_api->sql 558 | #define sqlite3_status sqlite3_api->status 559 | #define sqlite3_backup_finish sqlite3_api->backup_finish 560 | #define sqlite3_backup_init sqlite3_api->backup_init 561 | #define sqlite3_backup_pagecount sqlite3_api->backup_pagecount 562 | #define sqlite3_backup_remaining sqlite3_api->backup_remaining 563 | #define sqlite3_backup_step sqlite3_api->backup_step 564 | #define sqlite3_compileoption_get sqlite3_api->compileoption_get 565 | #define sqlite3_compileoption_used sqlite3_api->compileoption_used 566 | #define sqlite3_create_function_v2 sqlite3_api->create_function_v2 567 | #define sqlite3_db_config sqlite3_api->db_config 568 | #define sqlite3_db_mutex sqlite3_api->db_mutex 569 | #define sqlite3_db_status sqlite3_api->db_status 570 | #define sqlite3_extended_errcode sqlite3_api->extended_errcode 571 | #define sqlite3_log sqlite3_api->log 572 | #define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64 573 | #define sqlite3_sourceid sqlite3_api->sourceid 574 | #define sqlite3_stmt_status sqlite3_api->stmt_status 575 | #define sqlite3_strnicmp sqlite3_api->strnicmp 576 | #define sqlite3_unlock_notify sqlite3_api->unlock_notify 577 | #define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint 578 | #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint 579 | #define sqlite3_wal_hook sqlite3_api->wal_hook 580 | #define sqlite3_blob_reopen sqlite3_api->blob_reopen 581 | #define sqlite3_vtab_config sqlite3_api->vtab_config 582 | #define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict 583 | /* Version 3.7.16 and later */ 584 | #define sqlite3_close_v2 sqlite3_api->close_v2 585 | #define sqlite3_db_filename sqlite3_api->db_filename 586 | #define sqlite3_db_readonly sqlite3_api->db_readonly 587 | #define sqlite3_db_release_memory sqlite3_api->db_release_memory 588 | #define sqlite3_errstr sqlite3_api->errstr 589 | #define sqlite3_stmt_busy sqlite3_api->stmt_busy 590 | #define sqlite3_stmt_readonly sqlite3_api->stmt_readonly 591 | #define sqlite3_stricmp sqlite3_api->stricmp 592 | #define sqlite3_uri_boolean sqlite3_api->uri_boolean 593 | #define sqlite3_uri_int64 sqlite3_api->uri_int64 594 | #define sqlite3_uri_parameter sqlite3_api->uri_parameter 595 | #define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf 596 | #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 597 | /* Version 3.8.7 and later */ 598 | #define sqlite3_auto_extension sqlite3_api->auto_extension 599 | #define sqlite3_bind_blob64 sqlite3_api->bind_blob64 600 | #define sqlite3_bind_text64 sqlite3_api->bind_text64 601 | #define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension 602 | #define sqlite3_load_extension sqlite3_api->load_extension 603 | #define sqlite3_malloc64 sqlite3_api->malloc64 604 | #define sqlite3_msize sqlite3_api->msize 605 | #define sqlite3_realloc64 sqlite3_api->realloc64 606 | #define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension 607 | #define sqlite3_result_blob64 sqlite3_api->result_blob64 608 | #define sqlite3_result_text64 sqlite3_api->result_text64 609 | #define sqlite3_strglob sqlite3_api->strglob 610 | /* Version 3.8.11 and later */ 611 | #define sqlite3_value_dup sqlite3_api->value_dup 612 | #define sqlite3_value_free sqlite3_api->value_free 613 | #define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64 614 | #define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64 615 | /* Version 3.9.0 and later */ 616 | #define sqlite3_value_subtype sqlite3_api->value_subtype 617 | #define sqlite3_result_subtype sqlite3_api->result_subtype 618 | /* Version 3.10.0 and later */ 619 | #define sqlite3_status64 sqlite3_api->status64 620 | #define sqlite3_strlike sqlite3_api->strlike 621 | #define sqlite3_db_cacheflush sqlite3_api->db_cacheflush 622 | /* Version 3.12.0 and later */ 623 | #define sqlite3_system_errno sqlite3_api->system_errno 624 | /* Version 3.14.0 and later */ 625 | #define sqlite3_trace_v2 sqlite3_api->trace_v2 626 | #define sqlite3_expanded_sql sqlite3_api->expanded_sql 627 | /* Version 3.18.0 and later */ 628 | #define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid 629 | /* Version 3.20.0 and later */ 630 | #define sqlite3_prepare_v3 sqlite3_api->prepare_v3 631 | #define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3 632 | #define sqlite3_bind_pointer sqlite3_api->bind_pointer 633 | #define sqlite3_result_pointer sqlite3_api->result_pointer 634 | #define sqlite3_value_pointer sqlite3_api->value_pointer 635 | /* Version 3.22.0 and later */ 636 | #define sqlite3_vtab_nochange sqlite3_api->vtab_nochange 637 | #define sqlite3_value_nochange sqlite3_api->value_nochange 638 | #define sqlite3_vtab_collation sqlite3_api->vtab_collation 639 | /* Version 3.24.0 and later */ 640 | #define sqlite3_keyword_count sqlite3_api->keyword_count 641 | #define sqlite3_keyword_name sqlite3_api->keyword_name 642 | #define sqlite3_keyword_check sqlite3_api->keyword_check 643 | #define sqlite3_str_new sqlite3_api->str_new 644 | #define sqlite3_str_finish sqlite3_api->str_finish 645 | #define sqlite3_str_appendf sqlite3_api->str_appendf 646 | #define sqlite3_str_vappendf sqlite3_api->str_vappendf 647 | #define sqlite3_str_append sqlite3_api->str_append 648 | #define sqlite3_str_appendall sqlite3_api->str_appendall 649 | #define sqlite3_str_appendchar sqlite3_api->str_appendchar 650 | #define sqlite3_str_reset sqlite3_api->str_reset 651 | #define sqlite3_str_errcode sqlite3_api->str_errcode 652 | #define sqlite3_str_length sqlite3_api->str_length 653 | #define sqlite3_str_value sqlite3_api->str_value 654 | /* Version 3.25.0 and later */ 655 | #define sqlite3_create_window_function sqlite3_api->create_window_function 656 | /* Version 3.26.0 and later */ 657 | #define sqlite3_normalized_sql sqlite3_api->normalized_sql 658 | /* Version 3.28.0 and later */ 659 | #define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain 660 | #define sqlite3_value_frombind sqlite3_api->value_frombind 661 | /* Version 3.30.0 and later */ 662 | #define sqlite3_drop_modules sqlite3_api->drop_modules 663 | /* Version 3.31.0 and later */ 664 | #define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64 665 | #define sqlite3_uri_key sqlite3_api->uri_key 666 | #define sqlite3_filename_database sqlite3_api->filename_database 667 | #define sqlite3_filename_journal sqlite3_api->filename_journal 668 | #define sqlite3_filename_wal sqlite3_api->filename_wal 669 | /* Version 3.32.0 and later */ 670 | #define sqlite3_create_filename sqlite3_api->create_filename 671 | #define sqlite3_free_filename sqlite3_api->free_filename 672 | #define sqlite3_database_file_object sqlite3_api->database_file_object 673 | /* Version 3.34.0 and later */ 674 | #define sqlite3_txn_state sqlite3_api->txn_state 675 | /* Version 3.36.1 and later */ 676 | #define sqlite3_changes64 sqlite3_api->changes64 677 | #define sqlite3_total_changes64 sqlite3_api->total_changes64 678 | /* Version 3.37.0 and later */ 679 | #define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages 680 | /* Version 3.38.0 and later */ 681 | #define sqlite3_error_offset sqlite3_api->error_offset 682 | #define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value 683 | #define sqlite3_vtab_distinct sqlite3_api->vtab_distinct 684 | #define sqlite3_vtab_in sqlite3_api->vtab_in 685 | #define sqlite3_vtab_in_first sqlite3_api->vtab_in_first 686 | #define sqlite3_vtab_in_next sqlite3_api->vtab_in_next 687 | /* Version 3.39.0 and later */ 688 | #ifndef SQLITE_OMIT_DESERIALIZE 689 | #define sqlite3_deserialize sqlite3_api->deserialize 690 | #define sqlite3_serialize sqlite3_api->serialize 691 | #endif 692 | #define sqlite3_db_name sqlite3_api->db_name 693 | /* Version 3.40.0 and later */ 694 | #define sqlite3_value_encoding sqlite3_api->value_encoding 695 | /* Version 3.41.0 and later */ 696 | #define sqlite3_is_interrupted sqlite3_api->is_interrupted 697 | /* Version 3.43.0 and later */ 698 | #define sqlite3_stmt_explain sqlite3_api->stmt_explain 699 | /* Version 3.44.0 and later */ 700 | #define sqlite3_get_clientdata sqlite3_api->get_clientdata 701 | #define sqlite3_set_clientdata sqlite3_api->set_clientdata 702 | #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ 703 | 704 | #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) 705 | /* This case when the file really is being compiled as a loadable 706 | ** extension */ 707 | # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; 708 | # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; 709 | # define SQLITE_EXTENSION_INIT3 \ 710 | extern const sqlite3_api_routines *sqlite3_api; 711 | #else 712 | /* This case when the file is being statically linked into the 713 | ** application */ 714 | # define SQLITE_EXTENSION_INIT1 /*no-op*/ 715 | # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ 716 | # define SQLITE_EXTENSION_INIT3 /*no-op*/ 717 | #endif 718 | 719 | #endif /* SQLITE3EXT_H */ 720 | -------------------------------------------------------------------------------- /src/sqlitejs.c: -------------------------------------------------------------------------------- 1 | // 2 | // sqlitejs.c 3 | // sqlitejs 4 | // 5 | // Created by Marco Bambini on 31/03/25. 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "sqlitejs.h" 13 | #include "quickjs.h" 14 | #include "quickjs-libc.h" 15 | 16 | #ifndef SQLITE_CORE 17 | SQLITE_EXTENSION_INIT1 18 | #endif 19 | 20 | #ifdef _WIN32 21 | #define APIEXPORT __declspec(dllexport) 22 | #else 23 | #define APIEXPORT 24 | #endif 25 | 26 | typedef struct { 27 | JSRuntime *runtime; 28 | JSContext *context; 29 | sqlite3 *db; 30 | JSClassID rowSetClassID; 31 | } globaljs_context; 32 | 33 | typedef struct { 34 | bool inited; 35 | 36 | globaljs_context *js_ctx; // never to release 37 | JSContext *agg_ctx; // to release (windows and aggregate functions) 38 | 39 | const char *init_code; // release only if complete (aggregate functions only) 40 | const char *step_code; // release only if complete (scalar, collation, windows and aggregate functions) 41 | const char *final_code; // release only if complete (windows and aggregate functions) 42 | const char *value_code; // release only if complete (window functions only) 43 | const char *inverse_code; // release only if complete (window functions only) 44 | JSValue step_func; // to release (scalar, collation, windows and aggregate functions) 45 | JSValue final_func; // to release (windows and aggregate functions) 46 | JSValue value_func; // to release (window functions only) 47 | JSValue inverse_func; // to release (window functions only) 48 | } functionjs_context; 49 | 50 | static char *sqlite_strdup (const char *str); 51 | static bool js_global_init (JSContext *ctx, globaljs_context *js); 52 | static JSValue sqlite_value_to_js (JSContext *ctx, sqlite3_value *value); 53 | 54 | #define FUNCTION_TYPE_SCALAR "scalar" 55 | #define FUNCTION_TYPE_WINDOW "window" 56 | #define FUNCTION_TYPE_AGGREGATE "aggregate" 57 | #define FUNCTION_TYPE_COLLATION "collation" 58 | 59 | #define SAFE_STRCMP(a,b) (((a) != (b)) && ((a) == NULL || (b) == NULL || strcmp((a), (b)) != 0)) 60 | 61 | // MARK: - RowSet - 62 | 63 | typedef struct { 64 | int ncols; 65 | sqlite3_stmt *vm; 66 | } rowset; 67 | 68 | static void js_rowset_finalizer(JSRuntime *rt, JSValue val); 69 | static JSValue js_rowset_next(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); 70 | static JSValue js_rowset_get(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); 71 | static JSValue js_rowset_name(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); 72 | static JSValue js_rowset_to_array(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); 73 | 74 | // Define the Rowset class 75 | static const JSClassDef js_rowset_class = { 76 | "Rowset", 77 | .finalizer = js_rowset_finalizer, 78 | }; 79 | 80 | // Define the Rowset prototype with methods 81 | static const JSCFunctionListEntry js_rowset_proto_funcs[] = { 82 | JS_CFUNC_DEF("next", 0, js_rowset_next), 83 | JS_CFUNC_DEF("get", 1, js_rowset_get), 84 | JS_CFUNC_DEF("name", 1, js_rowset_name), 85 | JS_CFUNC_DEF("toArray", 0, js_rowset_to_array), 86 | }; 87 | 88 | static JSValue js_rowset_next(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { 89 | globaljs_context *js = JS_GetContextOpaque(ctx); 90 | rowset *rs = JS_GetOpaque(this_val, js->rowSetClassID); 91 | if (!rs) return JS_EXCEPTION; 92 | 93 | if (sqlite3_step(rs->vm) == SQLITE_ROW) return JS_TRUE; 94 | 95 | sqlite3_finalize(rs->vm); 96 | rs->vm = NULL; 97 | return JS_FALSE; 98 | } 99 | 100 | static JSValue js_rowset_get(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { 101 | globaljs_context *js = JS_GetContextOpaque(ctx); 102 | rowset *rs = JS_GetOpaque(this_val, js->rowSetClassID); 103 | if (!rs) return JS_EXCEPTION; 104 | 105 | uint32_t index = 0; 106 | JS_ToUint32(ctx, &index, argv[0]); 107 | if (index >= rs->ncols) return JS_EXCEPTION; 108 | 109 | sqlite3_value *value = sqlite3_column_value(rs->vm, (int)index); 110 | return sqlite_value_to_js(ctx, value); 111 | } 112 | 113 | static JSValue js_rowset_name(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { 114 | globaljs_context *js = JS_GetContextOpaque(ctx); 115 | rowset *rs = JS_GetOpaque(this_val, js->rowSetClassID); 116 | if (!rs) return JS_EXCEPTION; 117 | 118 | uint32_t index = 0; 119 | JS_ToUint32(ctx, &index, argv[0]); 120 | if (index >= rs->ncols) return JS_EXCEPTION; 121 | 122 | const char *name = sqlite3_column_name(rs->vm, (int)index); 123 | if (!name) return JS_EXCEPTION; 124 | 125 | return JS_NewString(ctx, name); 126 | } 127 | 128 | static JSValue js_rowset_to_array(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { 129 | globaljs_context *js = JS_GetContextOpaque(ctx); 130 | rowset *rs = JS_GetOpaque(this_val, js->rowSetClassID); 131 | if (!rs) return JS_EXCEPTION; 132 | 133 | JSValue result = JS_NewArray(ctx); 134 | if (JS_IsException(result)) return JS_EXCEPTION; 135 | 136 | int ncols = rs->ncols; 137 | int nrows = 0; 138 | while (true) { 139 | int rc = sqlite3_step(rs->vm); 140 | if (rc != SQLITE_ROW) break; 141 | 142 | JSValue row = JS_NewArray(ctx); 143 | if (JS_IsException(row)) return JS_EXCEPTION; 144 | 145 | for (int i=0; ivm, i); 147 | JSValue jvalue = sqlite_value_to_js(ctx, value); 148 | JS_SetPropertyUint32(ctx, row, i, jvalue); 149 | } 150 | 151 | JS_SetPropertyUint32(ctx, result, nrows++, row); 152 | } 153 | 154 | sqlite3_finalize(rs->vm); 155 | rs->vm = NULL; 156 | return result; 157 | } 158 | 159 | static void js_rowset_finalizer(JSRuntime *rt, JSValue val) { 160 | rowset *rs = (rowset *)JS_VALUE_GET_PTR(val); 161 | if (!rs) return; 162 | 163 | if (rs->vm) sqlite3_finalize(rs->vm); 164 | sqlite3_free(rs); 165 | } 166 | 167 | // MARK: - Initializer - 168 | 169 | static globaljs_context *globaljs_init (sqlite3 *db) { 170 | JSRuntime *rt = NULL; 171 | JSContext *ctx = NULL; 172 | 173 | globaljs_context *js = (globaljs_context *)sqlite3_malloc(sizeof(globaljs_context)); 174 | if (!js) return NULL; 175 | memset(js, 0, sizeof(globaljs_context)); 176 | 177 | rt = JS_NewRuntime(); 178 | if (!rt) goto abort_init; 179 | 180 | //JS_SetMemoryLimit(rt, 80 * 1024); 181 | //JS_SetMaxStackSize(rt, 10 * 1024); 182 | 183 | js_std_init_handlers(rt); 184 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); 185 | 186 | ctx = JS_NewContext(rt); 187 | if (!ctx) goto abort_init; 188 | 189 | js->db = db; 190 | js->runtime = rt; 191 | js->context = ctx; 192 | 193 | JS_SetContextOpaque(ctx, js); 194 | js_global_init(ctx, js); 195 | 196 | return js; 197 | 198 | abort_init: 199 | if (rt) JS_FreeRuntime(rt); 200 | if (ctx) JS_FreeContext(ctx); 201 | if (js) sqlite3_free(js); 202 | return NULL; 203 | } 204 | 205 | static void globaljs_free (globaljs_context *js) { 206 | if (!js) return; 207 | 208 | // order matters 209 | if (js->runtime) js_std_free_handlers(js->runtime); 210 | if (js->context) JS_FreeContext(js->context); 211 | if (js->runtime) JS_FreeRuntime(js->runtime); 212 | sqlite3_free(js); 213 | } 214 | 215 | static functionjs_context *functionjs_init (globaljs_context *jsctx, const char *init_code, const char *step_code, const char *final_code, const char *value_code, const char *inverse_code) { 216 | // make a copy of all the code 217 | functionjs_context *fctx = NULL; 218 | char *init_code_copy = NULL; 219 | char *step_code_copy = NULL; 220 | char *final_code_copy = NULL; 221 | char *value_code_copy = NULL; 222 | char *inverse_code_copy = NULL; 223 | 224 | fctx = (functionjs_context *)sqlite3_malloc(sizeof(functionjs_context)); 225 | if (!fctx) goto cleanup; 226 | memset(fctx, 0, sizeof(functionjs_context)); 227 | 228 | if (init_code) { 229 | init_code_copy = sqlite_strdup(init_code); 230 | if (!init_code_copy) goto cleanup; 231 | } 232 | 233 | if (step_code) { 234 | step_code_copy = sqlite_strdup(step_code); 235 | if (!step_code_copy) goto cleanup; 236 | } 237 | 238 | if (final_code) { 239 | final_code_copy = sqlite_strdup(final_code); 240 | if (!final_code_copy) goto cleanup; 241 | } 242 | 243 | if (value_code) { 244 | value_code_copy = sqlite_strdup(value_code); 245 | if (!value_code_copy) goto cleanup; 246 | } 247 | 248 | if (inverse_code) { 249 | inverse_code_copy = sqlite_strdup(inverse_code); 250 | if (!inverse_code_copy) goto cleanup; 251 | } 252 | 253 | fctx->inited = false; 254 | fctx->js_ctx = jsctx; 255 | fctx->agg_ctx = NULL; 256 | 257 | fctx->init_code = init_code_copy; 258 | fctx->step_code = step_code_copy; 259 | fctx->final_code = final_code_copy; 260 | fctx->value_code = value_code_copy; 261 | fctx->inverse_code = inverse_code_copy; 262 | 263 | fctx->step_func = JS_NULL; 264 | fctx->final_func = JS_NULL; 265 | fctx->value_func = JS_NULL; 266 | fctx->inverse_func = JS_NULL; 267 | 268 | return fctx; 269 | 270 | cleanup: 271 | if (init_code_copy) sqlite3_free(init_code_copy); 272 | if (step_code_copy) sqlite3_free(step_code_copy); 273 | if (final_code_copy) sqlite3_free(final_code_copy); 274 | if (value_code_copy) sqlite3_free(value_code_copy); 275 | if (inverse_code_copy) sqlite3_free(inverse_code_copy); 276 | if (fctx) sqlite3_free(fctx); 277 | return NULL; 278 | } 279 | 280 | static void functionjs_free (functionjs_context *fctx, bool complete) { 281 | if (!fctx) return; 282 | JSContext *context = (fctx->agg_ctx) ? fctx->agg_ctx : fctx->js_ctx->context; 283 | 284 | // always to release 285 | if (!JS_IsNull(fctx->step_func)) JS_FreeValue(context, fctx->step_func); 286 | if (!JS_IsNull(fctx->final_func)) JS_FreeValue(context, fctx->final_func); 287 | if (!JS_IsNull(fctx->value_func)) JS_FreeValue(context, fctx->value_func); 288 | if (!JS_IsNull(fctx->inverse_func)) JS_FreeValue(context, fctx->inverse_func); 289 | if (fctx->agg_ctx) JS_FreeContext(fctx->agg_ctx); 290 | 291 | fctx->step_func = JS_NULL; 292 | fctx->final_func = JS_NULL; 293 | fctx->value_func = JS_NULL; 294 | fctx->inverse_func = JS_NULL; 295 | fctx->agg_ctx = NULL; 296 | 297 | if (complete) { 298 | if (fctx->init_code) sqlite3_free((void *)fctx->init_code); 299 | if (fctx->step_code) sqlite3_free((void *)fctx->step_code); 300 | if (fctx->final_code) sqlite3_free((void *)fctx->final_code); 301 | if (fctx->value_code) sqlite3_free((void *)fctx->value_code); 302 | if (fctx->inverse_code) sqlite3_free((void *)fctx->inverse_code); 303 | sqlite3_free(fctx); 304 | } 305 | } 306 | 307 | // MARK: - Utils - 308 | 309 | static JSValue js_sqlite_exec (JSContext *ctx, sqlite3 *db, const char *sql, int argc, JSValueConst *argv) { 310 | sqlite3_stmt *vm = NULL; 311 | const char *tail = NULL; 312 | rowset *rs = NULL; 313 | 314 | // compile statement 315 | int rc = sqlite3_prepare_v2(db, sql, -1, &vm, &tail); 316 | if (rc != SQLITE_OK) goto abort_with_dberror; 317 | 318 | // count if statement contains bindings 319 | int nbind = sqlite3_bind_parameter_count(vm); 320 | if (nbind > 0 && argc > 0) { 321 | // loop to bind 322 | if (nbind > argc) nbind = argc; 323 | for (int i=1; i<=nbind; ++i) { 324 | 325 | } 326 | } 327 | 328 | // create and initialize internal rowset 329 | rs = (rowset *)sqlite3_malloc(sizeof(rowset)); 330 | if (!rs) goto abort_with_dberror; 331 | rs->vm = vm; 332 | rs->ncols = sqlite3_column_count(vm); 333 | 334 | // create Rowset JS object 335 | globaljs_context *js = JS_GetContextOpaque(ctx); 336 | JSValue obj = JS_NewObjectClass(ctx, js->rowSetClassID); 337 | if (JS_IsException(obj)) goto abort_with_jserror; 338 | JS_SetOpaque(obj, rs); 339 | JS_SetPropertyStr(ctx, obj, "columnCount", JS_NewInt32(ctx, rs->ncols)); 340 | 341 | return obj; 342 | 343 | abort_with_dberror: 344 | if (rs) { 345 | if (rs->vm) rs->vm = NULL; 346 | sqlite3_free(rs); 347 | } 348 | if (vm) sqlite3_finalize(vm); 349 | return JS_ThrowInternalError(ctx, "%s", sqlite3_errmsg(db)); 350 | 351 | abort_with_jserror: 352 | if (rs) { 353 | if (rs->vm) rs->vm = NULL; 354 | sqlite3_free(rs); 355 | } 356 | if (vm) sqlite3_finalize(vm); 357 | return obj; 358 | } 359 | 360 | static JSValue js_dbfunc_exec (JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { 361 | // check if we have at least one argument 362 | if (argc < 1) return JS_EXCEPTION; 363 | 364 | // get the SQL string from the first argument 365 | size_t len; 366 | const char *sql = JS_ToCStringLen(ctx, &len, argv[0]); 367 | if (!sql) return JS_EXCEPTION; 368 | 369 | // perform statement 370 | globaljs_context *js = JS_GetContextOpaque(ctx); 371 | JSValue value = js_sqlite_exec(ctx, js->db, sql, argc-1, argv); 372 | 373 | // free the string when done 374 | JS_FreeCString(ctx, sql); 375 | 376 | return value; 377 | } 378 | 379 | static bool js_global_init (JSContext *ctx, globaljs_context *js) { 380 | js_std_add_helpers(ctx, 0, NULL); 381 | 382 | // add any global objects or functions here 383 | JSValue global_obj = JS_GetGlobalObject(ctx); 384 | 385 | // create a new db object 386 | JSValue db_obj = JS_NewObject(ctx); 387 | JS_SetPropertyStr(ctx, db_obj, "exec", JS_NewCFunction(ctx, js_dbfunc_exec, "exec", 1)); 388 | JS_SetPropertyStr(ctx, global_obj, "db", db_obj); 389 | 390 | // register rowset class 391 | JS_NewClassID(js->runtime, &js->rowSetClassID); 392 | JS_NewClass(js->runtime, js->rowSetClassID, &js_rowset_class); 393 | JSValue proto = JS_NewObject(ctx); 394 | JS_SetPropertyFunctionList(ctx, proto, js_rowset_proto_funcs, sizeof(js_rowset_proto_funcs)/sizeof(js_rowset_proto_funcs[0])); 395 | JS_SetClassProto(ctx, js->rowSetClassID, proto); 396 | 397 | // register standard modules 398 | js_init_module_std(ctx, "std"); 399 | js_init_module_os(ctx, "os"); 400 | js_init_module_bjson(ctx, "bjson"); 401 | 402 | // release the global object reference 403 | JS_FreeValue(ctx, global_obj); 404 | 405 | // we don't free db_obj because it's now owned by the global object 406 | return true; 407 | } 408 | 409 | static void js_dump_globals (JSContext *ctx) { 410 | JSValue global_obj = JS_GetGlobalObject(ctx); 411 | JSPropertyEnum *props; 412 | uint32_t len; 413 | 414 | if (JS_GetOwnPropertyNames(ctx, &props, &len, global_obj, 415 | JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) == 0) { 416 | 417 | for (uint32_t i = 0; i < len; i++) { 418 | JSAtom atom = props[i].atom; 419 | const char *key = JS_AtomToCString(ctx, atom); 420 | JSValue val = JS_GetProperty(ctx, global_obj, atom); 421 | 422 | if (JS_IsFunction(ctx, val)) { 423 | // Try to get function source 424 | JSValue str = JS_ToString(ctx, val); 425 | const char *func_code = JS_ToCString(ctx, str); 426 | printf("%s\n", func_code ? func_code : "// [function: unknown source]"); 427 | JS_FreeCString(ctx, func_code); 428 | JS_FreeValue(ctx, str); 429 | } else { 430 | JSValue str = JS_JSONStringify(ctx, val, JS_UNDEFINED, JS_UNDEFINED); 431 | const char *val_str = JS_ToCString(ctx, str); 432 | printf("let %s = %s;\n", key, val_str ? val_str : "undefined"); 433 | JS_FreeCString(ctx, val_str); 434 | JS_FreeValue(ctx, str); 435 | } 436 | 437 | JS_FreeValue(ctx, val); 438 | JS_FreeCString(ctx, key); 439 | JS_FreeAtom(ctx, atom); 440 | } 441 | js_free(ctx, props); 442 | } 443 | JS_FreeValue(ctx, global_obj); 444 | } 445 | 446 | static void js_error_to_sqlite (sqlite3_context *context, JSContext *js_ctx, JSValue value, const char *default_error) { 447 | if (!default_error) default_error = "Unknown JavaScript exception"; 448 | const char *err_msg = NULL; 449 | JSValue exception = JS_NULL; 450 | 451 | if (JS_IsException(value)) { 452 | JSValue exception = JS_GetException(js_ctx); 453 | if (JS_IsObject(exception)) { 454 | JSValue message = JS_GetPropertyStr(js_ctx, exception, "message"); 455 | if (!JS_IsException(message) && JS_IsString(message)) { 456 | err_msg = JS_ToCString(js_ctx, message); 457 | } 458 | JS_FreeValue(js_ctx, message); 459 | } 460 | } 461 | 462 | // set a default error message and code 463 | sqlite3_result_error(context, (err_msg) ? err_msg : default_error, -1); 464 | sqlite3_result_error_code(context, SQLITE_ERROR); 465 | 466 | // clean-up 467 | if (err_msg) JS_FreeCString(js_ctx, err_msg); 468 | if (!JS_IsNull(exception)) JS_FreeValue(js_ctx, exception); 469 | } 470 | 471 | static bool js_value_to_sqlite (sqlite3_context *context, JSContext *js_ctx, JSValue value) { 472 | // check for exceptions first and convert it to a proper error message (if any) 473 | if (JS_IsException(value)) { 474 | js_error_to_sqlite(context, js_ctx, value, NULL); 475 | return false; 476 | } 477 | 478 | // check for null or undefined 479 | if (JS_IsNull(value) || JS_IsUndefined(value)) { 480 | sqlite3_result_null(context); 481 | return false; 482 | } 483 | 484 | // handle numbers 485 | if (JS_IsNumber(value)) { 486 | int tag = JS_VALUE_GET_TAG(value); 487 | if (tag == JS_TAG_INT) { 488 | int32_t num; 489 | JS_ToInt32(js_ctx, &num, value); 490 | sqlite3_result_int(context, num); 491 | } else if (tag == JS_TAG_FLOAT64) { 492 | double num; 493 | JS_ToFloat64(js_ctx, &num, value); 494 | sqlite3_result_double(context, num); 495 | } else { 496 | // handle BigInt if needed 497 | sqlite3_result_null(context); 498 | } 499 | return false; 500 | } 501 | 502 | // handle booleans 503 | if (JS_IsBool(value)) { 504 | sqlite3_result_int(context, JS_ToBool(js_ctx, value)); 505 | return false; 506 | } 507 | 508 | // handle strings 509 | if (JS_IsString(value)) { 510 | size_t len = 0; 511 | const char * str= JS_ToCStringLen(js_ctx, &len, value); 512 | if (str) { 513 | sqlite3_result_text(context, str, (int)len, SQLITE_TRANSIENT); 514 | JS_FreeCString(js_ctx, str); 515 | } else { 516 | sqlite3_result_error(context, "Failed to convert JS string", -1); 517 | } 518 | return false; 519 | } 520 | 521 | if (JS_IsObject(value)) { 522 | sqlite3_result_null(context); 523 | return true; 524 | } 525 | 526 | // fallback for unsupported types 527 | sqlite3_result_error(context, "Unsupported JS value type", -1); 528 | return false; 529 | } 530 | 531 | static bool js_setup_aggregate (sqlite3_context *context, globaljs_context *js, functionjs_context *fctx, const char *init_code, const char *step_code, const char *final_code, const char *value_code, const char *inverse_code) { 532 | 533 | // create a separate context for testing purpose 534 | JSContext *ctx = JS_NewContext(js->runtime); 535 | if (!ctx) { 536 | sqlite3_result_error(context, "Unable to create a JS context.", -1); 537 | return false; 538 | } 539 | 540 | // setup global object 541 | JS_SetContextOpaque(ctx, js); 542 | js_global_init(ctx, js); 543 | 544 | // init code is optional 545 | if (init_code) { 546 | JSValue result = JS_Eval(ctx, init_code, strlen(init_code), NULL, JS_EVAL_TYPE_GLOBAL); 547 | bool is_error = JS_IsException(result); 548 | if (is_error) js_error_to_sqlite(context, ctx, result, NULL); 549 | JS_FreeValue(ctx, result); 550 | if (is_error) return false; 551 | } 552 | 553 | JSValue step_func = JS_NULL; 554 | JSValue final_func = JS_NULL; 555 | JSValue value_func = JS_NULL; 556 | JSValue inverse_func = JS_NULL; 557 | 558 | // generate JavaScript functions 559 | step_func = JS_Eval(ctx, step_code, strlen(step_code), NULL, JS_EVAL_TYPE_GLOBAL); 560 | if (!JS_IsFunction(ctx, step_func)) goto cleanup; 561 | 562 | final_func = JS_Eval(ctx, final_code, strlen(final_code), NULL, JS_EVAL_TYPE_GLOBAL); 563 | if (!JS_IsFunction(ctx, final_func)) goto cleanup; 564 | 565 | if (value_code) { 566 | value_func = JS_Eval(ctx, value_code, strlen(value_code), NULL, JS_EVAL_TYPE_GLOBAL); 567 | if (!JS_IsFunction(ctx, value_func)) goto cleanup; 568 | } 569 | 570 | if (inverse_code) { 571 | inverse_func = JS_Eval(ctx, inverse_code, strlen(inverse_code), NULL, JS_EVAL_TYPE_GLOBAL); 572 | if (!JS_IsFunction(ctx, inverse_func)) goto cleanup; 573 | } 574 | 575 | // when here I am sure everything is OK 576 | if (fctx) { 577 | // setup a proper function aggregate context 578 | fctx->agg_ctx = ctx; 579 | fctx->step_func = step_func; 580 | fctx->final_func = final_func; 581 | fctx->value_func = value_func; 582 | fctx->inverse_func = inverse_func; 583 | fctx->inited = true; 584 | } 585 | return true; 586 | 587 | cleanup: 588 | if (!JS_IsFunction(ctx, step_func)) js_error_to_sqlite(context, ctx, step_func, "JavaScript step code must evaluate to a function in the form (function(args){ your_code_here })"); 589 | else if (!JS_IsFunction(ctx, final_func)) js_error_to_sqlite(context, ctx, final_func, "JavaScript final code must evaluate to a function in the form (function(){ your_code_here })"); 590 | else if (!JS_IsFunction(ctx, value_func)) js_error_to_sqlite(context, ctx, final_func, "JavaScript value code must evaluate to a function in the form (function(){ your_code_here })"); 591 | else if (!JS_IsFunction(ctx, inverse_func)) js_error_to_sqlite(context, ctx, step_func, "JavaScript inverse code must evaluate to a function in the form (function(args){ your_code_here })"); 592 | 593 | 594 | JS_FreeValue(ctx, step_func); 595 | JS_FreeValue(ctx, final_func); 596 | JS_FreeValue(ctx, value_func); 597 | JS_FreeValue(ctx, inverse_func); 598 | 599 | JS_FreeContext(ctx); 600 | return false; 601 | } 602 | 603 | static JSValue sqlite_value_to_js (JSContext *ctx, sqlite3_value *value) { 604 | int type = sqlite3_value_type(value); 605 | 606 | switch (type) { 607 | case SQLITE_NULL: 608 | return JS_NULL; 609 | break; 610 | 611 | case SQLITE_INTEGER: 612 | return JS_NewInt64(ctx, sqlite3_value_int64(value)); 613 | break; 614 | 615 | case SQLITE_FLOAT: 616 | return JS_NewFloat64(ctx, sqlite3_value_double(value)); 617 | break; 618 | 619 | case SQLITE_TEXT: 620 | return JS_NewString(ctx, (const char *)sqlite3_value_text(value)); 621 | break; 622 | 623 | case SQLITE_BLOB: { 624 | int size = sqlite3_value_bytes(value); 625 | const void *blob = sqlite3_value_blob(value); 626 | return JS_NewArrayBufferCopy(ctx, (const uint8_t *)blob, (size_t)size); 627 | } 628 | break; 629 | } 630 | 631 | return JS_NULL; 632 | } 633 | 634 | static const char *sqlite_value_text (sqlite3_value *value) { 635 | if (sqlite3_value_type(value) != SQLITE_TEXT) return NULL; 636 | return (const char *)sqlite3_value_text(value); 637 | } 638 | 639 | static char *sqlite_strdup (const char *str) { 640 | if (!str) return NULL; 641 | 642 | size_t len = strlen(str) + 1; 643 | char *result = (char*)sqlite3_malloc((int)len); 644 | if (result) memcpy(result, str, len); 645 | 646 | return result; 647 | } 648 | 649 | // MARK: - Execution - 650 | 651 | static void js_execute_commong (sqlite3_context *context, int nvalues, sqlite3_value **values, JSValue func, JSValue this_obj, bool return_value) { 652 | functionjs_context *fctx = (functionjs_context *)sqlite3_user_data(context); 653 | globaljs_context *js = fctx->js_ctx; 654 | 655 | JSContext *js_context = (fctx->agg_ctx) ? fctx->agg_ctx : js->context; 656 | 657 | // create JS array for arguments 658 | JSValue args = (values) ? JS_NewArray(js_context) : JS_NULL; 659 | for (int i=0; istep_func, JS_UNDEFINED, true); 677 | } 678 | 679 | static void js_execute_step (sqlite3_context *context, int nvalues, sqlite3_value **values) { 680 | functionjs_context *fctx = (functionjs_context *)sqlite3_user_data(context); 681 | globaljs_context *js = fctx->js_ctx; 682 | 683 | // if there is an init code then create a separate aggregate context 684 | // to avoid shared state corruption across parallel aggregates 685 | if (!fctx->inited) { 686 | // set up a new isolated environment for this aggregation 687 | if (js_setup_aggregate(context, js, fctx, fctx->init_code, fctx->step_code, fctx->final_code, fctx->value_code, fctx->inverse_code) == false) return; 688 | fctx->inited = true; 689 | } 690 | 691 | js_execute_commong(context, nvalues, values, fctx->step_func, JS_UNDEFINED, false); 692 | } 693 | 694 | static void js_execute_value (sqlite3_context *context) { 695 | functionjs_context *fctx = (functionjs_context *)sqlite3_user_data(context); 696 | js_execute_commong(context, 0, NULL, fctx->value_func, JS_UNDEFINED, true); 697 | } 698 | 699 | static void js_execute_inverse (sqlite3_context *context, int nvalues, sqlite3_value **values) { 700 | functionjs_context *fctx = (functionjs_context *)sqlite3_user_data(context); 701 | js_execute_commong(context, nvalues, values, fctx->inverse_func, JS_UNDEFINED, false); 702 | } 703 | 704 | static void js_execute_final (sqlite3_context *context) { 705 | functionjs_context *fctx = (functionjs_context *)sqlite3_user_data(context); 706 | js_execute_commong(context, 0, NULL, fctx->final_func, JS_UNDEFINED, true); 707 | functionjs_free(fctx, false); 708 | fctx->inited = false; 709 | } 710 | 711 | static int js_execute_collation (void *xdata, int len1, const void *v1, int len2, const void *v2) { 712 | functionjs_context *fctx = (functionjs_context *)xdata; 713 | globaljs_context *js = fctx->js_ctx; 714 | 715 | // create arguments 716 | JSValue val1 = (v1) ? JS_NewStringLen(js->context, (const char *)v1, (size_t)len1) : JS_NULL; 717 | JSValue val2 = (v2) ? JS_NewStringLen(js->context, (const char *)v2, (size_t)len2) : JS_NULL; 718 | JSValue args[] = {val1, val2}; 719 | 720 | // call the JavaScript function with arguments 721 | JSValue result = JS_Call(js->context, fctx->step_func, JS_UNDEFINED, 2, args); 722 | JS_FreeValue(js->context, val1); 723 | JS_FreeValue(js->context, val2); 724 | 725 | // default result if JS result is not a number 726 | int nresult = -1; 727 | if (JS_IsNumber(result)) JS_ToInt32(js->context, &nresult, result); 728 | JS_FreeValue(js->context, result); 729 | 730 | return nresult; 731 | } 732 | 733 | static void js_execute_cleanup (void *xdata) { 734 | if (!xdata) return; 735 | functionjs_free((functionjs_context *)xdata, true); 736 | } 737 | 738 | // MARK: - Functions - 739 | 740 | void js_version (sqlite3_context *context, bool internal_engine) { 741 | sqlite3_result_text(context, (internal_engine) ? quickjs_version() : sqlitejs_version(), -1, NULL); 742 | } 743 | 744 | void js_version1 (sqlite3_context *context, int argc, sqlite3_value **argv) { 745 | bool internal_engine = (sqlite3_value_int(argv[0]) != 0); 746 | js_version(context, internal_engine); 747 | } 748 | 749 | void js_version0 (sqlite3_context *context, int argc, sqlite3_value **argv) { 750 | js_version(context, false); 751 | } 752 | 753 | bool js_add_to_table (sqlite3_context *context, const char *type, const char *name, const char *init_code, const char *step_code, const char *final_code, const char *value_code, const char *inverse_code) { 754 | 755 | // add function to table under the following conditions: 756 | // 1. js_functions table exists 757 | // 2. the same function with the same code is not already in the table (we prevented replacing it with the same values to avoid unnecessary CRDT operations in case this table is synced with sqlite-sync) 758 | sqlite3 *db = sqlite3_context_db_handle(context); 759 | bool force_reinsert = false; 760 | sqlite3_stmt *vm = NULL; 761 | 762 | // query table first 763 | const char *sql = "SELECT kind,init_code,step_code,final_code,value_code,inverse_code FROM js_functions WHERE name=?1 LIMIT 1;"; 764 | int rc = sqlite3_prepare_v2(db, sql, -1, &vm, NULL); 765 | if (rc != SQLITE_OK) { 766 | // table js_functions does not exist 767 | sqlite3_finalize(vm); 768 | return true; 769 | } 770 | 771 | rc = sqlite3_step(vm); 772 | if (rc == SQLITE_DONE) { 773 | // no functions with that name exist, so add it to the table 774 | force_reinsert = true; 775 | goto insert_function; 776 | } if (rc != SQLITE_ROW) { 777 | // something bad happened, just abort 778 | sqlite3_finalize(vm); 779 | return false; 780 | } 781 | 782 | const char *type2 = (const char *)sqlite3_column_text(vm, 0); 783 | const char *init_code2 = (sqlite3_column_type(vm, 1) == SQLITE_NULL) ? NULL : (const char *)sqlite3_column_text(vm, 1); 784 | const char *step_code2 = (sqlite3_column_type(vm, 2) == SQLITE_NULL) ? NULL : (const char *)sqlite3_column_text(vm, 2); 785 | const char *final_code2 = (sqlite3_column_type(vm, 3) == SQLITE_NULL) ? NULL : (const char *)sqlite3_column_text(vm, 3); 786 | const char *value_code2 = (sqlite3_column_type(vm, 4) == SQLITE_NULL) ? NULL : (const char *)sqlite3_column_text(vm, 4); 787 | const char *inverse_code2 = (sqlite3_column_type(vm, 5) == SQLITE_NULL) ? NULL : (const char *)sqlite3_column_text(vm, 5); 788 | 789 | if ((strcasecmp(type, type2) != 0) || 790 | SAFE_STRCMP(init_code, init_code2) || 791 | SAFE_STRCMP(step_code, step_code2) || 792 | SAFE_STRCMP(final_code, final_code2) || 793 | SAFE_STRCMP(value_code, value_code2) || 794 | SAFE_STRCMP(inverse_code, inverse_code2)) force_reinsert = true; 795 | 796 | // the following logic: 797 | // if ((init_code == NULL) && (init_code2 != NULL)) force_reinsert = true; 798 | // if ((init_code != NULL) && (init_code2 == NULL)) force_reinsert = true; 799 | // if ((init_code != NULL) && (init_code2 != NULL) && (strcmp(init_code, init_code2) != 0)) force_reinsert = true; 800 | // can be simplified as: 801 | // if ((init_code != init_code2) && (init_code == NULL || init_code2 == NULL || strcmp(init_code, init_code2) != 0)) force_reinsert = true; 802 | // as a macro: 803 | // SAFE_STRCMP(a,b) (((a) != (b)) && ((a) == NULL || (b) == NULL || strcmp((a), (b)) != 0)) 804 | 805 | // we use strcmp because even if a single character case changes, we force the update of that function 806 | 807 | insert_function: 808 | sqlite3_finalize(vm); 809 | if (force_reinsert == false) return true; 810 | 811 | sql = "REPLACE INTO js_functions (name, kind, init_code, step_code, final_code, value_code, inverse_code) VALUES (?, ?, ?, ?, ?, ?, ?);"; 812 | rc = sqlite3_prepare(db, sql, -1, &vm, NULL); 813 | if (rc == SQLITE_OK) { 814 | rc = sqlite3_bind_text(vm, 1, name, -1, NULL); 815 | rc = sqlite3_bind_text(vm, 2, type, -1, NULL); 816 | rc = (init_code == NULL) ? sqlite3_bind_null(vm, 3) : sqlite3_bind_text(vm, 3, init_code, -1, NULL); 817 | rc = (step_code == NULL) ? sqlite3_bind_null(vm, 4) : sqlite3_bind_text(vm, 4, step_code, -1, NULL); 818 | rc = (final_code == NULL) ? sqlite3_bind_null(vm, 5) : sqlite3_bind_text(vm, 5, final_code, -1, NULL); 819 | rc = (value_code == NULL) ? sqlite3_bind_null(vm, 6) : sqlite3_bind_text(vm, 6, value_code, -1, NULL); 820 | rc = (inverse_code == NULL) ? sqlite3_bind_null(vm, 7) : sqlite3_bind_text(vm, 7, inverse_code, -1, NULL); 821 | } 822 | 823 | rc = sqlite3_step(vm); 824 | sqlite3_finalize(vm); 825 | 826 | return (rc == SQLITE_DONE); 827 | } 828 | 829 | bool js_create_common (sqlite3_context *context, const char *type, const char *name, const char *init_code, const char *step_code, const char *final_code, const char *value_code, const char *inverse_code, bool is_load) { 830 | 831 | globaljs_context *js = (globaljs_context *)sqlite3_user_data(context); 832 | 833 | bool is_scalar = (strcasecmp(type, FUNCTION_TYPE_SCALAR) == 0); 834 | bool is_aggregate = (is_scalar) ? false : (strcasecmp(type, FUNCTION_TYPE_AGGREGATE) == 0); 835 | bool is_window = (is_aggregate) ? false : (strcasecmp(type, FUNCTION_TYPE_WINDOW) == 0); 836 | bool is_collation = (is_window) ? false : (strcasecmp(type, FUNCTION_TYPE_COLLATION) == 0); 837 | bool step_code_null = (is_scalar || is_collation); 838 | 839 | if (is_aggregate || is_window) { 840 | // sanity check aggregate code 841 | if (js_setup_aggregate(context, js, NULL, init_code, step_code, final_code, NULL, NULL) == false) return false; 842 | } 843 | 844 | // create function context 845 | functionjs_context *fctx = functionjs_init(js, init_code, (step_code_null) ? NULL : step_code, final_code, value_code, inverse_code); 846 | if (!fctx) { 847 | sqlite3_result_error_nomem(context); 848 | return false; 849 | } 850 | 851 | if (is_scalar || is_collation) { 852 | // prepare the JavaScript function 853 | JSValue func = JS_Eval(js->context, step_code, strlen(step_code), NULL, JS_EVAL_TYPE_GLOBAL); 854 | if (!JS_IsFunction(js->context, func)) { 855 | const char *err_msg = (is_scalar) ? "JavaScript code must evaluate to a function in the form (function(args){ your_code_here })" : "JavaScript code must evaluate to a function in the form (function(str1, str2){ your_code_here })"; 856 | js_error_to_sqlite(context, js->context, func, err_msg); 857 | functionjs_free(fctx, true); 858 | return false; 859 | } 860 | fctx->step_func = func; 861 | } 862 | 863 | int rc = SQLITE_OK; 864 | if (is_scalar) rc = sqlite3_create_function_v2(sqlite3_context_db_handle(context), name, -1, SQLITE_UTF8, (void *)fctx, js_execute_scalar, NULL, NULL, js_execute_cleanup); 865 | else if (is_aggregate) rc = sqlite3_create_function_v2(sqlite3_context_db_handle(context), name, -1, SQLITE_UTF8, (void *)fctx, NULL, js_execute_step, js_execute_final, js_execute_cleanup); 866 | else if (is_window) rc = sqlite3_create_window_function(sqlite3_context_db_handle(context), name, -1, SQLITE_UTF8, (void *)fctx, js_execute_step, js_execute_final, js_execute_value, js_execute_inverse, js_execute_cleanup); 867 | else if (is_collation) rc = sqlite3_create_collation_v2(sqlite3_context_db_handle(context), name, SQLITE_UTF8, (void *)fctx, js_execute_collation, js_execute_cleanup); 868 | 869 | if (rc == SQLITE_BUSY) { 870 | // Due to this: https://www3.sqlite.org/src/info/cabab62bc10568d4 871 | // it is not possible to update or delete a previously registered function 872 | // within the same database connection. 873 | // There is nothing we can do because this is an SQLite implementation detail. 874 | // Function updates must be performed using a separate database connection. 875 | sqlite3_result_error(context, "Function updates must be performed using a separate database connection.", -1); 876 | } 877 | 878 | if ((is_load == false) && (rc == SQLITE_OK)) { 879 | js_add_to_table(context, type, name, init_code, step_code, final_code, value_code, inverse_code); 880 | } 881 | 882 | // js_execute_cleanup is automatically called in case of error 883 | (rc == SQLITE_OK) ? sqlite3_result_int(context, SQLITE_OK) : sqlite3_result_error_code(context, rc); 884 | return (rc == SQLITE_OK); 885 | } 886 | 887 | void js_create_scalar (sqlite3_context *context, int argc, sqlite3_value **argv) { 888 | // get/check parameters first 889 | const char *name = sqlite_value_text(argv[0]); 890 | const char *code = sqlite_value_text(argv[1]); 891 | 892 | if (name == NULL || code == NULL) { 893 | sqlite3_result_error(context, "Two parameters of type TEXT are required", -1); 894 | return; 895 | } 896 | 897 | js_create_common(context, FUNCTION_TYPE_SCALAR, name, NULL, code, NULL, NULL, NULL, false); 898 | } 899 | 900 | void js_create_aggregate (sqlite3_context *context, int argc, sqlite3_value **argv) { 901 | // get/check parameters first 902 | const char *name = sqlite_value_text(argv[0]); 903 | const char *init_code = sqlite_value_text(argv[1]); 904 | const char *step_code = sqlite_value_text(argv[2]); 905 | const char *final_code = sqlite_value_text(argv[3]); 906 | 907 | if (name == NULL || step_code == NULL || final_code == NULL) { 908 | sqlite3_result_error(context, "The required name, step and final code parameters must be of type TEXT", -1); 909 | return; 910 | } 911 | 912 | js_create_common(context, FUNCTION_TYPE_AGGREGATE, name, init_code, step_code, final_code, NULL, NULL, false); 913 | } 914 | 915 | void js_create_window (sqlite3_context *context, int argc, sqlite3_value **argv) { 916 | // get/check parameters first 917 | const char *name = sqlite_value_text(argv[0]); 918 | const char *init_code = sqlite_value_text(argv[1]); 919 | const char *step_code = sqlite_value_text(argv[2]); 920 | const char *final_code = sqlite_value_text(argv[3]); 921 | const char *value_code = sqlite_value_text(argv[4]); 922 | const char *inverse_code = sqlite_value_text(argv[5]); 923 | 924 | if (name == NULL || step_code == NULL || final_code == NULL || value_code == NULL || inverse_code == NULL) { 925 | sqlite3_result_error(context, "The required name, step, final, value and inverse code parameters must be of type TEXT", -1); 926 | return; 927 | } 928 | 929 | js_create_common(context, FUNCTION_TYPE_WINDOW, name, init_code, step_code, final_code, value_code, inverse_code, false); 930 | } 931 | 932 | void js_create_collation (sqlite3_context *context, int argc, sqlite3_value **argv) { 933 | // get/check parameters first 934 | const char *name = sqlite_value_text(argv[0]); 935 | const char *code = sqlite_value_text(argv[1]); 936 | 937 | if (name == NULL || code == NULL) { 938 | sqlite3_result_error(context, "Two parameters of type TEXT are required", -1); 939 | return; 940 | } 941 | 942 | js_create_common(context, FUNCTION_TYPE_COLLATION, name, NULL, code, NULL, NULL, NULL, false); 943 | } 944 | 945 | void js_eval (sqlite3_context *context, int argc, sqlite3_value **argv) { 946 | globaljs_context *data = (globaljs_context *)sqlite3_user_data(context); 947 | 948 | const char *code = (const char *)sqlite3_value_text(argv[0]); 949 | if (!code) { 950 | sqlite3_result_error(context, "A parameter of type TEXT is required", -1); 951 | return; 952 | } 953 | 954 | JSValue value = JS_Eval(data->context, code, strlen(code), NULL, JS_EVAL_TYPE_GLOBAL); 955 | bool is_object = js_value_to_sqlite(context, data->context, value); 956 | if (!is_object) JS_FreeValue(data->context, value); 957 | } 958 | 959 | static void js_load_fromfile (sqlite3_context *context, int argc, sqlite3_value **argv, bool is_blob) { 960 | const char *path = (const char *)sqlite3_value_text(argv[0]); 961 | if (!path) { 962 | sqlite3_result_error(context, "A parameter of type TEXT is required", -1); 963 | return; 964 | } 965 | 966 | FILE *f = fopen(path, (is_blob) ? "rb": "r"); 967 | if (!f) { 968 | sqlite3_result_error(context, "Unable to open the file", -1); 969 | return; 970 | } 971 | 972 | fseek(f, 0, SEEK_END); 973 | size_t length = (size_t)ftell(f); 974 | fseek(f, 0, SEEK_SET); 975 | 976 | char *buffer = (char *)sqlite3_malloc((int)length); 977 | if (!buffer) { 978 | fclose(f); 979 | sqlite3_result_error_nomem(context); 980 | return; 981 | } 982 | 983 | size_t nread = fread(buffer, length, 1, f); 984 | if (nread == length) { 985 | (is_blob) ? sqlite3_result_blob(context, buffer, (int)length, sqlite3_free) : sqlite3_result_text(context, buffer, (int)length, sqlite3_free); 986 | } else { 987 | sqlite3_result_error(context, "Unable to correctly read the file", -1); 988 | if (buffer) sqlite3_free(buffer); 989 | } 990 | 991 | fclose(f); 992 | } 993 | 994 | void js_load_text (sqlite3_context *context, int argc, sqlite3_value **argv) { 995 | js_load_fromfile(context, argc, argv, false); 996 | } 997 | 998 | void js_load_blob (sqlite3_context *context, int argc, sqlite3_value **argv) { 999 | js_load_fromfile(context, argc, argv, true); 1000 | } 1001 | 1002 | int js_load_from_table_callback (void *xdata, int ncols, char **values, char **names) { 1003 | sqlite3_context *context = (sqlite3_context *)xdata; 1004 | assert(ncols == 7); 1005 | 1006 | const char *type = values[1]; 1007 | 1008 | const char *name = values[0]; 1009 | const char *init_code = values[2]; 1010 | const char *step_code = values[3]; 1011 | const char *final_code = values[4]; 1012 | const char *value_code = values[5]; 1013 | const char *inverse_code = values[6]; 1014 | 1015 | bool result = js_create_common(context, type, name, init_code, step_code, final_code, value_code, inverse_code, true); 1016 | return (result) ? SQLITE_OK : SQLITE_ERROR; 1017 | } 1018 | 1019 | int js_load_from_table (sqlite3_context *context) { 1020 | sqlite3 *db = sqlite3_context_db_handle(context); 1021 | const char *sql = "SELECT * FROM js_functions;"; 1022 | return sqlite3_exec(db, sql, js_load_from_table_callback, context, NULL); 1023 | } 1024 | 1025 | void js_init_table (sqlite3_context *context, bool load_functions) { 1026 | sqlite3 *db = sqlite3_context_db_handle(context); 1027 | const char *sql = "CREATE TABLE IF NOT EXISTS js_functions (" 1028 | "name TEXT PRIMARY KEY COLLATE NOCASE," // Name of the SQLite function or collation 1029 | "kind TEXT NOT NULL," // 'scalar', 'aggregate', 'window', 'collation' 1030 | "init_code TEXT DEFAULT NULL," // Only for aggregate/window 1031 | "step_code TEXT DEFAULT NULL," // Used in all functions 1032 | "final_code TEXT DEFAULT NULL," // Only for aggregate/window 1033 | "value_code TEXT DEFAULT NULL," // Only for window 1034 | "inverse_code TEXT DEFAULT NULL" // Only for window 1035 | ");"; 1036 | 1037 | // create table 1038 | int rc = sqlite3_exec(db, sql, NULL, NULL, NULL); 1039 | if (rc != SQLITE_OK) { 1040 | sqlite3_result_error_code(context, rc); 1041 | return; 1042 | } 1043 | 1044 | // load js functions from table 1045 | if (load_functions) rc = js_load_from_table(context); 1046 | 1047 | sqlite3_result_int(context, rc); 1048 | } 1049 | 1050 | void js_init_table1 (sqlite3_context *context, int argc, sqlite3_value **argv) { 1051 | bool load_functions = (sqlite3_value_int(argv[0]) != 0); 1052 | js_init_table(context, load_functions); 1053 | } 1054 | 1055 | void js_init_table0 (sqlite3_context *context, int argc, sqlite3_value **argv) { 1056 | js_init_table(context, false); 1057 | } 1058 | 1059 | // MARK: - 1060 | 1061 | const char *sqlitejs_version (void) { 1062 | return SQLITE_JS_VERSION; 1063 | } 1064 | 1065 | const char *quickjs_version (void) { 1066 | return JS_GetVersion(); 1067 | } 1068 | 1069 | APIEXPORT int sqlite3_js_init (sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { 1070 | #ifndef SQLITE_CORE 1071 | SQLITE_EXTENSION_INIT2(pApi); 1072 | #endif 1073 | 1074 | globaljs_context *data = globaljs_init(db); 1075 | if (!data) return SQLITE_NOMEM; 1076 | 1077 | const char *f_name[] = {"js_version", "js_version", "js_create_scalar", "js_create_aggregate", "js_create_window", "js_create_collation", "js_eval", "js_load_text", "js_load_blob", "js_init_table", "js_init_table"}; 1078 | const void *f_ptr[] = {js_version0, js_version1, js_create_scalar, js_create_aggregate, js_create_window, js_create_collation, js_eval, js_load_text, js_load_blob, js_init_table0, js_init_table1}; 1079 | int f_arg[] = {0, 1, 2, 4, 6, 2, 1, 1, 1, 0, 1}; 1080 | 1081 | size_t f_count = sizeof(f_name) / sizeof(const char *); 1082 | for (size_t i=0; i 12 | #include 13 | #ifndef SQLITE_CORE 14 | #include "sqlite3ext.h" 15 | #else 16 | #include "sqlite3.h" 17 | #endif 18 | 19 | #define SQLITE_JS_VERSION "1.1.3" 20 | 21 | int sqlite3_js_init (sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi); 22 | const char *sqlitejs_version (void); 23 | const char *quickjs_version (void); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /test/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // sqlitejs 4 | // 5 | // Created by Marco Bambini on 31/03/25. 6 | // 7 | 8 | #include 9 | #include "sqlite3.h" 10 | #include "sqlitejs.h" 11 | 12 | #define DB_PATH "js_functions.sqlite" 13 | 14 | static int print_results_callback(void *data, int argc, char **argv, char **names) { 15 | for (int i = 0; i < argc; i++) { 16 | printf("%s: %s ", names[i], argv[i] ? argv[i] : "NULL"); 17 | } 18 | printf("\n"); 19 | return SQLITE_OK; 20 | } 21 | 22 | int db_exec (sqlite3 *db, const char *sql) { 23 | int rc = sqlite3_exec(db, sql, print_results_callback, NULL, NULL); 24 | if (rc != SQLITE_OK) printf("Error while executing %s: %s\n", sql, sqlite3_errmsg(db)); 25 | return rc; 26 | } 27 | 28 | // MARK: - 29 | 30 | int test_serialization (const char *db_path, bool load_functions, int nstep) { 31 | sqlite3 *db = NULL; 32 | int rc = sqlite3_open(db_path, &db); 33 | if (rc != SQLITE_OK) goto abort_test; 34 | 35 | #if JS_LOAD_EMBEDDED 36 | rc = sqlite3_js_init(db, NULL, NULL); 37 | #else 38 | // enable load extension 39 | rc = sqlite3_enable_load_extension(db, 1); 40 | if (rc != SQLITE_OK) goto abort_test; 41 | 42 | rc = db_exec(db, "SELECT load_extension('./dist/js');"); 43 | if (rc != SQLITE_OK) goto abort_test; 44 | #endif 45 | 46 | rc = db_exec(db, (load_functions) ? "SELECT js_init_table(1);" : "SELECT js_init_table();"); 47 | if (rc != SQLITE_OK) goto abort_test; 48 | 49 | printf("Step %d...\n", nstep); 50 | 51 | if (nstep == 1) { 52 | rc = db_exec(db, "SELECT js_create_scalar('SuperFunction', '(function(args){return args[0];})')"); 53 | if (rc == SQLITE_OK) rc = db_exec(db, "SELECT SuperFunction(123), SuperFunction(12.3);"); 54 | } 55 | if (nstep == 2) { 56 | rc = db_exec(db, "SELECT js_create_scalar('SuperFunction', '(function(args){return args[0] * 2;})')"); 57 | if (rc == SQLITE_OK) rc = db_exec(db, "SELECT SuperFunction(123), SuperFunction(12.3);"); 58 | } 59 | if (nstep == 3) { 60 | rc = db_exec(db, "SELECT SuperFunction(123), SuperFunction(12.3);"); 61 | } 62 | if (rc != SQLITE_OK) goto abort_test; 63 | printf("\n"); 64 | 65 | abort_test: 66 | if (rc != SQLITE_OK) printf("Error: %s\n", sqlite3_errmsg(db)); 67 | if (db) sqlite3_close(db); 68 | return rc; 69 | } 70 | 71 | int test_execution (void) { 72 | sqlite3 *db = NULL; 73 | int rc = sqlite3_open(":memory:", &db); 74 | if (rc != SQLITE_OK) goto abort_test; 75 | 76 | #if JS_LOAD_EMBEDDED 77 | rc = sqlite3_js_init(db, NULL, NULL); 78 | #else 79 | // enable load extension 80 | rc = sqlite3_enable_load_extension(db, 1); 81 | if (rc != SQLITE_OK) goto abort_test; 82 | 83 | rc = db_exec(db, "SELECT load_extension('./dist/js');"); 84 | if (rc != SQLITE_OK) goto abort_test; 85 | #endif 86 | 87 | // context 88 | printf("Testing context\n"); 89 | rc = db_exec(db, "SELECT js_eval('x = 100;');"); 90 | rc = db_exec(db, "SELECT js_eval('x = x*2;');"); 91 | rc = db_exec(db, "SELECT js_eval('function test1(n) {return n*x;}');"); 92 | rc = db_exec(db, "SELECT js_eval('test1(50);');"); 93 | 94 | // eval 95 | printf("\nTesting js_eval\n"); 96 | rc = db_exec(db, "SELECT js_eval('136*10');"); 97 | rc = db_exec(db, "SELECT js_eval('Math.cos(13);');"); 98 | rc = db_exec(db, "SELECT js_eval('Math.random();');"); 99 | 100 | // scalar 101 | printf("\nTesting js_create_scalar\n"); 102 | rc = db_exec(db, "SELECT js_create_scalar('Cos', '(function(args){return Math.cos(args[0]);})')"); 103 | rc = db_exec(db, "SELECT Cos(123), cos(12.3);"); 104 | rc = db_exec(db, "SELECT js_create_scalar('Sin', '(function(args){return Math.sin(args[0]);})')"); 105 | rc = db_exec(db, "SELECT Sin(123), sin(12.3);"); 106 | 107 | // aggregate 108 | printf("\nTesting js_create_aggregate\n"); 109 | rc = db_exec(db, "SELECT js_create_aggregate('Median', 'prod = 1; n = 0;', '(function(args){n++; prod = prod * args[0];})', '(function(){return Math.pow(prod, 1/n);})');"); 110 | rc = db_exec(db, "CREATE TABLE data(val INTEGER);"); 111 | rc = db_exec(db, "INSERT INTO data(val) VALUES (2), (4), (8);"); 112 | rc = db_exec(db, "SELECT Median(val) FROM data;"); 113 | rc = db_exec(db, "INSERT INTO data(val) VALUES (10), (12), (14), (16), (18), (20);"); 114 | rc = db_exec(db, "SELECT Median(val) FROM data;"); 115 | 116 | // db object 117 | printf("\nTesting db.exec\n"); 118 | rc = db_exec(db, "SELECT js_eval('let rs = db.exec(''SELECT * FROM data;''); console.log(`rowset = ${rs.toArray()}`);');"); 119 | 120 | // collation 121 | printf("\nTesting js_create_collation\n"); 122 | const char *collation_js_function = "(function(str1,str2){" 123 | // Check if either string starts with 'A' or 'a'" 124 | "const str1StartsWithA = str1.length > 0 && (str1[0].toLowerCase() === ''a'');" 125 | "const str2StartsWithA = str2.length > 0 && (str2[0].toLowerCase() === ''a'');" 126 | // If one starts with A and the other does not, prioritize the one with A 127 | "if (str1StartsWithA && !str2StartsWithA) return -1;" 128 | "if (!str1StartsWithA && str2StartsWithA) return 1;" 129 | // Otherwise, perform a case-insensitive string comparison 130 | "return str1.toLowerCase().localeCompare(str2.toLowerCase());" 131 | "})"; 132 | 133 | char sql[1024]; 134 | snprintf(sql, sizeof(sql), "SELECT js_create_collation('A_FIRST', '%s')", collation_js_function); 135 | 136 | rc = db_exec(db, sql); 137 | 138 | // create test table and insert data 139 | rc = db_exec(db, 140 | "CREATE TABLE test(name TEXT);" 141 | "INSERT INTO test VALUES('Zebra');" 142 | "INSERT INTO test VALUES('Apple');" 143 | "INSERT INTO test VALUES('banana');" 144 | "INSERT INTO test VALUES('Carrot');" 145 | "INSERT INTO test VALUES('acorn');"); 146 | 147 | printf("Standard collation (lexicographical):\n"); 148 | rc = db_exec(db, "SELECT name FROM test ORDER BY name;"); 149 | 150 | printf("\nCustom collation (A_FIRST):\n"); 151 | rc = db_exec(db, "SELECT name FROM test ORDER BY name COLLATE A_FIRST;"); 152 | 153 | // window 154 | printf("\nTesting js_create_window\n"); 155 | rc = db_exec(db, "SELECT js_create_window('sumint', 'sum = 0;', '(function(args){sum += args[0];})', '(function(){return sum;})', '(function(){return sum;})', '(function(args){sum -= args[0];})');"); 156 | 157 | // example from https://www.sqlite.org/windowfunctions.html#udfwinfunc 158 | rc = db_exec(db, 159 | "CREATE TABLE t3(x, y);" 160 | "INSERT INTO t3 VALUES('a', 4), ('b', 5), ('c', 3), ('d', 8), ('e', 1);"); 161 | 162 | rc = db_exec(db, "SELECT x, sumint(y) OVER (ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS sum_y FROM t3 ORDER BY x;"); 163 | 164 | 165 | abort_test: 166 | if (rc != SQLITE_OK) printf("Error: %s\n", sqlite3_errmsg(db)); 167 | if (db) sqlite3_close(db); 168 | return rc; 169 | } 170 | 171 | // MARK: - 172 | 173 | int main (void) { 174 | printf("SQLite-JS version: %s (engine: %s)\n\n", sqlitejs_version(), quickjs_version()); 175 | 176 | int rc = test_execution(); 177 | 178 | rc = test_serialization(DB_PATH, false, 1); // create and execute original implementations 179 | rc = test_serialization(DB_PATH, false, 2); // update functions previously registered in the js_functions table 180 | rc = test_serialization(DB_PATH, true, 3); // load the new implementations 181 | 182 | return rc; 183 | } 184 | --------------------------------------------------------------------------------