388
416
src/env_properties.hCopy file name to clipboard Expand all lines: src/env_properties.h +2 Lines changed: 2 additions & 0 deletions Original file line number Diff line number Diff line change 117
117
V(crypto_rsa_pss_string, "rsa-pss") \
118
118
V(cwd_string, "cwd") \
119
119
V(data_string, "data") \
120
+ V(database_string, "database") \
120
121
V(default_is_true_string, "defaultIsTrue") \
121
122
V(deserialize_info_string, "deserializeInfo") \
122
123
V(dest_string, "dest") \
362
363
V(subject_string, "subject") \
363
364
V(subjectaltname_string, "subjectaltname") \
364
365
V(syscall_string, "syscall") \
366
+ V(table_string, "table") \
365
367
V(target_string, "target") \
366
368
V(thread_id_string, "threadId") \
367
369
V(ticketkeycallback_string, "onticketkeycallback") \
Original file line number Diff line number Diff line change @@ -158,6 +158,16 @@ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, int errcode) {
158
158
}
159
159
}
160
160
161
+ inline MaybeLocal NullableSQLiteStringToValue (Isolate* isolate,
162
+ const char * str) {
163
+ if (str == nullptr ) {
164
+ return Null (isolate);
165
+ }
166
+
167
+ return String::NewFromUtf8 (isolate, str, NewStringType::kInternalized )
168
+ .As ();
169
+ }
170
+
161
171
class BackupJob : public ThreadPoolWork {
162
172
public:
163
173
explicit BackupJob (Environment* env,
@@ -1918,6 +1928,72 @@ void StatementSync::Run(const FunctionCallbackInfo& args) {
1918
1928
args.GetReturnValue ().Set (result);
1919
1929
}
1920
1930
1931
+ void StatementSync::Columns (const FunctionCallbackInfo& args) {
1932
+ StatementSync* stmt;
1933
+ ASSIGN_OR_RETURN_UNWRAP (&stmt, args.This ());
1934
+ Environment* env = Environment::GetCurrent (args);
1935
+ THROW_AND_RETURN_ON_BAD_STATE (
1936
+ env, stmt->IsFinalized (), " statement has been finalized" );
1937
+ int num_cols = sqlite3_column_count (stmt->statement_ );
1938
+ Isolate* isolate = env->isolate ();
1939
+ LocalVector cols (isolate);
1940
+ LocalVector col_keys (isolate,
1941
+ {env->column_string (),
1942
+ env->database_string (),
1943
+ env->name_string (),
1944
+ env->table_string (),
1945
+ env->type_string ()});
1946
+ Local value;
1947
+
1948
+ cols.reserve (num_cols);
1949
+ for (int i = 0 ; i < num_cols; ++i) {
1950
+ LocalVector col_values (isolate);
1951
+ col_values.reserve (col_keys.size ());
1952
+
1953
+ if (!NullableSQLiteStringToValue (
1954
+ isolate, sqlite3_column_origin_name (stmt->statement_ , i))
1955
+ .ToLocal (&value)) {
1956
+ return ;
1957
+ }
1958
+ col_values.emplace_back (value);
1959
+
1960
+ if (!NullableSQLiteStringToValue (
1961
+ isolate, sqlite3_column_database_name (stmt->statement_ , i))
1962
+ .ToLocal (&value)) {
1963
+ return ;
1964
+ }
1965
+ col_values.emplace_back (value);
1966
+
1967
+ if (!stmt->ColumnNameToName (i).ToLocal (&value)) {
1968
+ return ;
1969
+ }
1970
+ col_values.emplace_back (value);
1971
+
1972
+ if (!NullableSQLiteStringToValue (
1973
+ isolate, sqlite3_column_table_name (stmt->statement_ , i))
1974
+ .ToLocal (&value)) {
1975
+ return ;
1976
+ }
1977
+ col_values.emplace_back (value);
1978
+
1979
+ if (!NullableSQLiteStringToValue (
1980
+ isolate, sqlite3_column_decltype (stmt->statement_ , i))
1981
+ .ToLocal (&value)) {
1982
+ return ;
1983
+ }
1984
+ col_values.emplace_back (value);
1985
+
1986
+ Local column = Object::New (isolate,
1987
+ Null (isolate),
1988
+ col_keys.data (),
1989
+ col_values.data (),
1990
+ col_keys.size ());
1991
+ cols.emplace_back (column);
1992
+ }
1993
+
1994
+ args.GetReturnValue ().Set (Array::New (isolate, cols.data (), cols.size ()));
1995
+ }
1996
+
1921
1997
void StatementSync::SourceSQLGetter (const FunctionCallbackInfo& args) {
1922
1998
StatementSync* stmt;
1923
1999
ASSIGN_OR_RETURN_UNWRAP (&stmt, args.This ());
@@ -2040,6 +2116,8 @@ Local StatementSync::GetConstructorTemplate(
2040
2116
SetProtoMethod (isolate, tmpl, " all" , StatementSync::All);
2041
2117
SetProtoMethod (isolate, tmpl, " get" , StatementSync::Get);
2042
2118
SetProtoMethod (isolate, tmpl, " run" , StatementSync::Run);
2119
+ SetProtoMethodNoSideEffect (
2120
+ isolate, tmpl, " columns" , StatementSync::Columns);
2043
2121
SetSideEffectFreeGetter (isolate,
2044
2122
tmpl,
2045
2123
FIXED_ONE_BYTE_STRING (isolate, " sourceSQL" ),
Original file line number Diff line number Diff line change @@ -119,6 +119,7 @@ class StatementSync : public BaseObject {
119
119
static void Iterate (const v8::FunctionCallbackInfo& args);
120
120
static void Get (const v8::FunctionCallbackInfo& args);
121
121
static void Run (const v8::FunctionCallbackInfo& args);
122
+ static void Columns (const v8::FunctionCallbackInfo& args);
122
123
static void SourceSQLGetter (const v8::FunctionCallbackInfo& args);
123
124
static void ExpandedSQLGetter (
124
125
const v8::FunctionCallbackInfo& args);
Original file line number Diff line number Diff line change
1
+ 'use strict' ;
2
+ require ( '../common' ) ;
3
+ const assert = require ( 'node:assert' ) ;
4
+ const { DatabaseSync } = require ( 'node:sqlite' ) ;
5
+ const { suite, test } = require ( 'node:test' ) ;
6
+
7
+ suite ( 'StatementSync.prototype.columns()' , ( ) => {
8
+ test ( 'returns column metadata for core SQLite types' , ( ) => {
9
+ const db = new DatabaseSync ( ':memory:' ) ;
10
+ db . exec ( `CREATE TABLE test (
11
+ col1 INTEGER,
12
+ col2 REAL,
13
+ col3 TEXT,
14
+ col4 BLOB,
15
+ col5 NULL
16
+ )` ) ;
17
+ const stmt = db . prepare ( 'SELECT col1, col2, col3, col4, col5 FROM test' ) ;
18
+ assert . deepStrictEqual ( stmt . columns ( ) , [
19
+ {
20
+ __proto__ : null ,
21
+ column : 'col1' ,
22
+ database : 'main' ,
23
+ name : 'col1' ,
24
+ table : 'test' ,
25
+ type : 'INTEGER' ,
26
+ } ,
27
+ {
28
+ __proto__ : null ,
29
+ column : 'col2' ,
30
+ database : 'main' ,
31
+ name : 'col2' ,
32
+ table : 'test' ,
33
+ type : 'REAL' ,
34
+ } ,
35
+ {
36
+ __proto__ : null ,
37
+ column : 'col3' ,
38
+ database : 'main' ,
39
+ name : 'col3' ,
40
+ table : 'test' ,
41
+ type : 'TEXT' ,
42
+ } ,
43
+ {
44
+ __proto__ : null ,
45
+ column : 'col4' ,
46
+ database : 'main' ,
47
+ name : 'col4' ,
48
+ table : 'test' ,
49
+ type : 'BLOB' ,
50
+ } ,
51
+ {
52
+ __proto__ : null ,
53
+ column : 'col5' ,
54
+ database : 'main' ,
55
+ name : 'col5' ,
56
+ table : 'test' ,
57
+ type : null ,
58
+ } ,
59
+ ] ) ;
60
+ } ) ;
61
+
62
+ test ( 'supports statements using multiple tables' , ( ) => {
63
+ const db = new DatabaseSync ( ':memory:' ) ;
64
+ db . exec ( `
65
+ CREATE TABLE test1 (value1 INTEGER);
66
+ CREATE TABLE test2 (value2 INTEGER);
67
+ ` ) ;
68
+ const stmt = db . prepare ( 'SELECT value1, value2 FROM test1, test2' ) ;
69
+ assert . deepStrictEqual ( stmt . columns ( ) , [
70
+ {
71
+ __proto__ : null ,
72
+ column : 'value1' ,
73
+ database : 'main' ,
74
+ name : 'value1' ,
75
+ table : 'test1' ,
76
+ type : 'INTEGER' ,
77
+ } ,
78
+ {
79
+ __proto__ : null ,
80
+ column : 'value2' ,
81
+ database : 'main' ,
82
+ name : 'value2' ,
83
+ table : 'test2' ,
84
+ type : 'INTEGER' ,
85
+ } ,
86
+ ] ) ;
87
+ } ) ;
88
+
89
+ test ( 'supports column aliases' , ( ) => {
90
+ const db = new DatabaseSync ( ':memory:' ) ;
91
+ db . exec ( `CREATE TABLE test (value INTEGER)` ) ;
92
+ const stmt = db . prepare ( 'SELECT value AS foo FROM test' ) ;
93
+ assert . deepStrictEqual ( stmt . columns ( ) , [
94
+ {
95
+ __proto__ : null ,
96
+ column : 'value' ,
97
+ database : 'main' ,
98
+ name : 'foo' ,
99
+ table : 'test' ,
100
+ type : 'INTEGER' ,
101
+ } ,
102
+ ] ) ;
103
+ } ) ;
104
+
105
+ test ( 'supports column expressions' , ( ) => {
106
+ const db = new DatabaseSync ( ':memory:' ) ;
107
+ db . exec ( `CREATE TABLE test (value INTEGER)` ) ;
108
+ const stmt = db . prepare ( 'SELECT value + 1, value FROM test' ) ;
109
+ assert . deepStrictEqual ( stmt . columns ( ) , [
110
+ {
111
+ __proto__ : null ,
112
+ column : null ,
113
+ database : null ,
114
+ name : 'value + 1' ,
115
+ table : null ,
116
+ type : null ,
117
+ } ,
118
+ {
119
+ __proto__ : null ,
120
+ column : 'value' ,
121
+ database : 'main' ,
122
+ name : 'value' ,
123
+ table : 'test' ,
124
+ type : 'INTEGER' ,
125
+ } ,
126
+ ] ) ;
127
+ } ) ;
128
+
129
+ test ( 'supports subqueries' , ( ) => {
130
+ const db = new DatabaseSync ( ':memory:' ) ;
131
+ db . exec ( `CREATE TABLE test (value INTEGER)` ) ;
132
+ const stmt = db . prepare ( 'SELECT * FROM (SELECT * FROM test)' ) ;
133
+ assert . deepStrictEqual ( stmt . columns ( ) , [
134
+ {
135
+ __proto__ : null ,
136
+ column : 'value' ,
137
+ database : 'main' ,
138
+ name : 'value' ,
139
+ table : 'test' ,
140
+ type : 'INTEGER' ,
141
+ } ,
142
+ ] ) ;
143
+ } ) ;
144
+
145
+ test ( 'supports statements that do not return data' , ( ) => {
146
+ const db = new DatabaseSync ( ':memory:' ) ;
147
+ db . exec ( 'CREATE TABLE test (value INTEGER)' ) ;
148
+ const stmt = db . prepare ( 'INSERT INTO test (value) VALUES (?)' ) ;
149
+ assert . deepStrictEqual ( stmt . columns ( ) , [ ] ) ;
150
+ } ) ;
151
+
152
+ test ( 'throws if the statement is finalized' , ( ) => {
153
+ const db = new DatabaseSync ( ':memory:' ) ;
154
+ db . exec ( 'CREATE TABLE test (value INTEGER)' ) ;
155
+ const stmt = db . prepare ( 'SELECT value FROM test' ) ;
156
+ db . close ( ) ;
157
+ assert . throws ( ( ) => {
158
+ stmt . columns ( ) ;
159
+ } , / s t a t e m e n t h a s b e e n f i n a l i z e d / ) ;
160
+ } ) ;
161
+ } ) ;
You can’t perform that action at this time.
0 commit comments