1+ /* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
2+
3+ /******************************************************************************
4+ *
5+ * You may not use the identified files except in compliance with the Apache
6+ * License, Version 2.0 (the "License.")
7+ *
8+ * You may obtain a copy of the License at
9+ * http://www.apache.org/licenses/LICENSE-2.0.
10+ *
11+ * Unless required by applicable law or agreed to in writing, software
12+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+ *
15+ * See the License for the specific language governing permissions and
16+ * limitations under the License.
17+ *
18+ * The node-oracledb test suite uses 'mocha', 'should' and 'async'.
19+ * See LICENSE.md for relevant licenses.
20+ *
21+ * NAME
22+ * 65. uninitializedLob.js
23+ *
24+ * DESCRIPTION
25+ * This test is provided by GitHub user for issue #344
26+ * It tests an uninitialized LOB returns from a PL/SQL block.
27+ *
28+ * NUMBERING RULE
29+ * Test numbers follow this numbering rule:
30+ * 1 - 20 are reserved for basic functional tests
31+ * 21 - 50 are reserved for data type supporting tests
32+ * 51 onwards are for other tests
33+ *
34+ *****************************************************************************/
35+ 'use strict' ;
36+
37+ var oracledb = require ( 'oracledb' ) ;
38+ var async = require ( 'async' ) ;
39+ var should = require ( 'should' ) ;
40+ var crypto = require ( 'crypto' ) ;
41+ var stream = require ( 'stream' ) ;
42+ var dbConfig = require ( './dbconfig.js' ) ;
43+
44+ describe ( '65. uninitializedLob.js' , function ( ) {
45+
46+ if ( dbConfig . externalAuth ) {
47+ var credential = { externalAuth : true , connectString : dbConfig . connectString } ;
48+ } else {
49+ var credential = dbConfig ;
50+ }
51+
52+ var connection = null ;
53+ before ( function ( done ) {
54+ async . series ( [
55+ function ( callback ) {
56+ oracledb . getConnection ( credential , function ( err , conn ) {
57+ should . not . exist ( err ) ;
58+ connection = conn ;
59+ callback ( ) ;
60+ } ) ;
61+ } ,
62+ function createTab ( callback ) {
63+ var proc = "BEGIN \n" +
64+ " DECLARE \n" +
65+ " e_table_exists EXCEPTION; \n" +
66+ " PRAGMA EXCEPTION_INIT(e_table_exists, -00942);\n " +
67+ " BEGIN \n" +
68+ " EXECUTE IMMEDIATE ('DROP TABLE testlobdpi'); \n" +
69+ " EXCEPTION \n" +
70+ " WHEN e_table_exists \n" +
71+ " THEN NULL; \n" +
72+ " END; \n" +
73+ " EXECUTE IMMEDIATE (' \n" +
74+ " CREATE TABLE testlobdpi ( \n" +
75+ " id NUMBER NOT NULL PRIMARY KEY, \n" +
76+ " spoc_cm_id NUMBER, \n" +
77+ " created_timestamp TIMESTAMP(5) DEFAULT SYSTIMESTAMP, \n" +
78+ " modified_timestamp TIMESTAMP(5) DEFAULT SYSTIMESTAMP \n" +
79+ " ) \n" +
80+ " '); \n" +
81+ "END; " ;
82+
83+ connection . execute (
84+ proc ,
85+ function ( err ) {
86+ should . not . exist ( err ) ;
87+ callback ( ) ;
88+ }
89+ ) ;
90+ } ,
91+ function createSeq ( callback ) {
92+ var proc = "BEGIN \n" +
93+ " DECLARE \n" +
94+ " e_sequence_exists EXCEPTION; \n" +
95+ " PRAGMA EXCEPTION_INIT(e_sequence_exists, -02289);\n " +
96+ " BEGIN \n" +
97+ " EXECUTE IMMEDIATE ('DROP SEQUENCE testlobdpi_seq'); \n" +
98+ " EXCEPTION \n" +
99+ " WHEN e_sequence_exists \n" +
100+ " THEN NULL; \n" +
101+ " END; \n" +
102+ " EXECUTE IMMEDIATE (' \n" +
103+ " CREATE SEQUENCE testlobdpi_seq INCREMENT BY 1 START WITH 1 NOMAXVALUE CACHE 50 ORDER \n" +
104+ " '); \n" +
105+ "END; " ;
106+
107+ connection . execute (
108+ proc ,
109+ function ( err ) {
110+ should . not . exist ( err ) ;
111+ callback ( ) ;
112+ }
113+ ) ;
114+ } ,
115+ function ( callback ) {
116+ var proc = "create or replace trigger testlobdpi_rbi \n" +
117+ " before insert on testlobdpi referencing old as old new as new \n" +
118+ " for each row \n" +
119+ "begin \n" +
120+ " :new.id := testlobdpi_seq.nextval;\n" +
121+ "end;" ;
122+ connection . execute (
123+ proc ,
124+ function ( err ) {
125+ should . not . exist ( err ) ;
126+ callback ( ) ;
127+ }
128+ ) ;
129+ } ,
130+ function ( callback ) {
131+ var proc = "create or replace trigger testlobdpi_rbu \n" +
132+ " before update on testlobdpi referencing old as old new as new \n" +
133+ " for each row \n" +
134+ "begin \n" +
135+ " :new.modified_timestamp := systimestamp;\n" +
136+ "end;" ;
137+ connection . execute (
138+ proc ,
139+ function ( err ) {
140+ should . not . exist ( err ) ;
141+ callback ( ) ;
142+ }
143+ ) ;
144+ } ,
145+ function ( callback ) {
146+ var sql = "ALTER TABLE testlobdpi ADD (blob_1 BLOB, unit32_1 NUMBER, date_1 TIMESTAMP(5), " +
147+ " string_1 VARCHAR2(250), CONSTRAINT string_1_uk UNIQUE (string_1))" ;
148+
149+ connection . execute (
150+ sql ,
151+ function ( err ) {
152+ should . not . exist ( err ) ;
153+ callback ( ) ;
154+ }
155+ ) ;
156+ }
157+ ] , done ) ;
158+ } ) // before
159+
160+ after ( function ( done ) {
161+ async . series ( [
162+ function ( callback ) {
163+ connection . execute (
164+ "DROP SEQUENCE testlobdpi_seq" ,
165+ function ( err ) {
166+ should . not . exist ( err ) ;
167+ callback ( ) ;
168+ }
169+ ) ;
170+ } ,
171+ function ( callback ) {
172+ connection . execute (
173+ "DROP TABLE testlobdpi" ,
174+ function ( err ) {
175+ should . not . exist ( err ) ;
176+ callback ( ) ;
177+ }
178+ ) ;
179+ } ,
180+ function ( callback ) {
181+ connection . release ( function ( err ) {
182+ should . not . exist ( err ) ;
183+ callback ( ) ;
184+ } ) ;
185+ }
186+ ] , done ) ;
187+ } ) // after
188+
189+ it ( '65.1 an uninitialized Lob is returned from a PL/SQL block' , function ( done ) {
190+ // async's times applies a function n times in series.
191+ async . timesSeries ( 3 , function ( n , next ) {
192+ var string_1 = n % 2 ;
193+ var proc = "DECLARE \n" +
194+ " row_count NUMBER := 0;" +
195+ " negative_one NUMBER := -1;" +
196+ "BEGIN \n" +
197+ " SELECT COUNT(*) INTO row_count FROM testlobdpi WHERE (string_1 = :string_1);" +
198+ " IF (row_count = 0 ) THEN\n" +
199+ " INSERT INTO testlobdpi (blob_1, string_1, spoc_cm_id) \n" +
200+ " VALUES (empty_blob(), :string_1, :spoc_cm_id) \n" +
201+ " RETURNING id, blob_1 INTO :id, :blob_1; \n" +
202+ " ELSE \n" +
203+ " :id := negative_one;\n" +
204+ " :blob_1 := null; \n" +
205+ " END IF;\n" +
206+ "END; " ;
207+
208+ connection . execute (
209+ proc ,
210+ {
211+ id : { type : oracledb . NUMBER , dir : oracledb . BIND_OUT } ,
212+ blob_1 : { type : oracledb . BLOB , dir : oracledb . BIND_OUT } ,
213+ string_1 : string_1 ,
214+ spoc_cm_id : 1
215+ } ,
216+ { outFormat : oracledb . OBJECT , autoCommit : false } ,
217+ function ( err , result ) {
218+ if ( err ) {
219+ console . error ( err . message ) ;
220+ return next ( err ) ;
221+ }
222+
223+ //console.log(n + ':',result);
224+
225+ if ( result . outBinds . id == - 1 ) {
226+ // a dup was found
227+ return next ( null )
228+ }
229+
230+ var randomBlob = new Buffer ( 0 ) ;
231+ crypto . randomBytes ( 16 , function ( ex , buf ) {
232+ var passthrough = new stream . PassThrough ( ) ;
233+ passthrough . on ( 'error' , function ( err ) {
234+ should . not . exist ( err ) ;
235+ } ) ;
236+
237+ result . outBinds . blob_1 . on ( 'error' , function ( err ) {
238+ should . not . exist ( err ) ;
239+ } )
240+
241+ result . outBinds . blob_1 . on ( 'finish' , function ( err ) {
242+ next ( err ) ;
243+ } ) ;
244+
245+ passthrough . write ( buf , function ( ) {
246+ passthrough . pipe ( result . outBinds . blob_1 ) ;
247+ passthrough . end ( ) ;
248+ } ) ;
249+ } ) ;
250+
251+ }
252+ ) ;
253+ } , function ( err ) {
254+ should . not . exist ( err ) ;
255+ done ( ) ;
256+ } ) ;
257+ } ) //65.1
258+ } )
0 commit comments