Compare commits
23 Commits
v7.3.0
...
e7b2ead0e2
| Author | SHA1 | Date | |
|---|---|---|---|
| e7b2ead0e2 | |||
| a89657b0b8 | |||
| 4ee15e1b6e | |||
| ed40df6295 | |||
| 6d590c050d | |||
| 47f9a54f97 | |||
| 17b0d72fbf | |||
| 0269c2421d | |||
| 5b260e4915 | |||
| 5290410a17 | |||
| dc9041aaec | |||
| b0dc441d68 | |||
| b0fc3eb5af | |||
| d9980e866d | |||
| 52ae3404ee | |||
| eecb4f4f53 | |||
| 744345af81 | |||
| 7694d1b0fb | |||
| d8010d4c0c | |||
| a57b49c936 | |||
| a84ba41ea9 | |||
| dc200646f7 | |||
| e273e870ef |
@@ -126,7 +126,7 @@ jobs:
|
||||
replace-in-files --regex='"hosturl".*' --replacement='hosturl:"http://localhost:4200",' ./cypress.config.ts
|
||||
cat ./cypress.config.ts
|
||||
# Start frontend and run cypress
|
||||
npx ng serve --host 0.0.0.0 --port 4200 & npx wait-on http://localhost:4200 && npx cypress run --browser chrome --spec "cypress/e2e/liveness.cy.ts,cypress/e2e/editor.cy.ts,cypress/e2e/excel-multi-load.cy.ts,cypress/e2e/excel.cy.ts,cypress/e2e/csv.cy.ts,cypress/e2e/filtering.cy.ts,cypress/e2e/licensing.cy.ts"
|
||||
npx ng serve --host 0.0.0.0 --port 4200 & npx wait-on http://localhost:4200 && npx cypress run --browser chrome --spec "cypress/e2e/csv-limited.cy.ts,cypress/e2e/liveness.cy.ts,cypress/e2e/editor.cy.ts,cypress/e2e/excel-multi-load.cy.ts,cypress/e2e/excel.cy.ts,cypress/e2e/csv.cy.ts,cypress/e2e/filtering.cy.ts,cypress/e2e/licensing.cy.ts"
|
||||
|
||||
- name: Zip Cypress videos
|
||||
if: always()
|
||||
|
||||
@@ -136,7 +136,7 @@ jobs:
|
||||
replace-in-files --regex='"hosturl".*' --replacement='hosturl:"http://localhost:4200",' ./cypress.config.ts
|
||||
cat ./cypress.config.ts
|
||||
# Start frontend and run cypress
|
||||
npx ng serve --host 0.0.0.0 --port 4200 & npx wait-on http://localhost:4200 && npx cypress run --browser chrome --spec "cypress/e2e/liveness.cy.ts,cypress/e2e/editor.cy.ts,cypress/e2e/excel-multi-load.cy.ts,cypress/e2e/excel.cy.ts,cypress/e2e/csv.cy.ts,cypress/e2e/filtering.cy.ts,cypress/e2e/licensing.cy.ts"
|
||||
npx ng serve --host 0.0.0.0 --port 4200 & npx wait-on http://localhost:4200 && npx cypress run --browser chrome --spec "cypress/e2e/csv-limited.cy.ts,cypress/e2e/liveness.cy.ts,cypress/e2e/editor.cy.ts,cypress/e2e/excel-multi-load.cy.ts,cypress/e2e/excel.cy.ts,cypress/e2e/csv.cy.ts,cypress/e2e/filtering.cy.ts,cypress/e2e/licensing.cy.ts"
|
||||
|
||||
- name: Zip Cypress videos
|
||||
if: always()
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
## [7.4.1](https://git.datacontroller.io/dc/dc/compare/v7.4.0...v7.4.1) (2026-03-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* support for SASIOSNF engine (SNOW alias) plus meta assignment ([7694d1b](https://git.datacontroller.io/dc/dc/commit/7694d1b0fb2bd0407c8598147fbae87a00d889a8))
|
||||
|
||||
# [7.4.0](https://git.datacontroller.io/dc/dc/compare/v7.3.0...v7.4.0) (2026-02-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cli bump for mf_getscheme support ([a84ba41](https://git.datacontroller.io/dc/dc/commit/a84ba41ea9f0c97ae24f0a572b8cf5ec200f2132))
|
||||
* missing upcase on SNOW section, plus local sasjs target ([dc20064](https://git.datacontroller.io/dc/dc/commit/dc200646f7df2fd1910841f392c314532aae7581))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* SAS code changes for snowflake support ([e273e87](https://git.datacontroller.io/dc/dc/commit/e273e870efbf7875db869b760f2c7b1f39d571ae))
|
||||
|
||||
# [7.3.0](https://git.datacontroller.io/dc/dc/compare/v7.2.8...v7.3.0) (2026-02-10)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
const username = Cypress.env('username')
|
||||
const password = Cypress.env('password')
|
||||
const hostUrl = Cypress.env('hosturl')
|
||||
const appLocation = Cypress.env('appLocation')
|
||||
const longerCommandTimeout = Cypress.env('longerCommandTimeout')
|
||||
const serverType = Cypress.env('serverType')
|
||||
const libraryToOpenIncludes = Cypress.env(`libraryToOpenIncludes_${serverType}`)
|
||||
const fixturePath = 'csvs/'
|
||||
|
||||
context('csv file upload restriction (free tier): ', function () {
|
||||
this.beforeEach(() => {
|
||||
cy.visit(hostUrl + appLocation)
|
||||
|
||||
cy.get('body').then(($body) => {
|
||||
const usernameInput = $body.find('input.username')[0]
|
||||
|
||||
if (usernameInput && !Cypress.dom.isHidden(usernameInput)) {
|
||||
cy.get('input.username').type(username)
|
||||
cy.get('input.password').type(password)
|
||||
cy.get('.login-group button').click()
|
||||
}
|
||||
})
|
||||
|
||||
cy.get('.app-loading', { timeout: longerCommandTimeout }).should(
|
||||
'not.exist'
|
||||
)
|
||||
|
||||
// Skip licensing page if presented - continue with free tier
|
||||
cy.url().then((url) => {
|
||||
if (url.includes('licensing')) {
|
||||
cy.get('button').contains('Continue with free tier').click()
|
||||
}
|
||||
})
|
||||
|
||||
visitPage('home')
|
||||
})
|
||||
|
||||
it('1 | File upload is restricted on free tier', () => {
|
||||
openTableFromTree(libraryToOpenIncludes, 'mpe_x_test')
|
||||
|
||||
// Click upload button - should show feature locked modal
|
||||
cy.get('.buttonBar button:last-child').should('exist').click()
|
||||
|
||||
cy.get('.modal-title').should('contain', 'Locked Feature (File Upload)')
|
||||
})
|
||||
})
|
||||
|
||||
const openTableFromTree = (libNameIncludes: string, tablename: string) => {
|
||||
cy.get('.app-loading', { timeout: longerCommandTimeout })
|
||||
.should('not.exist')
|
||||
.then(() => {
|
||||
cy.get('.nav-tree clr-tree > clr-tree-node', {
|
||||
timeout: longerCommandTimeout
|
||||
}).then((treeNodes: any) => {
|
||||
let targetLib
|
||||
|
||||
for (let node of treeNodes) {
|
||||
if (node.innerText.toLowerCase().includes(libNameIncludes)) {
|
||||
targetLib = node
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
cy.get(targetLib).within(() => {
|
||||
cy.get('.clr-tree-node-content-container > button').click()
|
||||
|
||||
cy.get('.clr-treenode-link').then((innerNodes: any) => {
|
||||
for (let innerNode of innerNodes) {
|
||||
if (innerNode.innerText.toLowerCase().includes(tablename)) {
|
||||
innerNode.click()
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const attachFile = (filename: string, callback?: any) => {
|
||||
cy.get('.buttonBar button:last-child')
|
||||
.should('exist')
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.get('input[type="file"]#file-upload')
|
||||
.attachFile(`/${fixturePath}/${filename}`)
|
||||
.then(() => {
|
||||
if (callback) callback()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const visitPage = (url: string) => {
|
||||
cy.visit(`${hostUrl}${appLocation}/#/${url}`)
|
||||
}
|
||||
@@ -4,7 +4,11 @@ PRIMARY_KEY_FIELD,SOME_CHAR,SOME_DROPDOWN,SOME_NUM,SOME_DATE,SOME_DATETIME,SOME_
|
||||
2,even more dummy data,Option 3,42,12FEB1960,01JAN1960:00:00:42,0:02:22,3,44
|
||||
3,"It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told: It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told: It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told: It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told:",Option 2,1613.001,27FEB1961,01JAN1960:00:07:03,0:00:44,3,44
|
||||
4,if you can fill the unforgiving minute,Option 1,1613.0011235,02AUG1971,29MAY1973:06:12:03,0:06:52,3,44
|
||||
1010,10 bottles of beer on the wall,Option 1,0.9153696885,04MAR1962,01JAN1960:12:47:55,0:01:40,92,76
|
||||
1010,"10 bottles of beer
|
||||
|
||||
|
||||
|
||||
on the wall",Option 1,0.9153696885,04MAR1962,01JAN1960:12:47:55,0:01:40,92,76
|
||||
1011,11 bottles of beer on the wall,Option 1,0.3531217558,29MAR1960,01JAN1960:03:33:24,0:01:03,80,29
|
||||
1012,12 bottles of beer on the wall,Option 1,0.6743748717,02AUG1962,01JAN1960:07:25:59,0:00:10,16,98
|
||||
1013,13 bottles of beer on the wall,Option 1,0.1305445992,11SEP1960,01JAN1960:13:51:32,0:00:35,73,15
|
||||
|
||||
|
@@ -55,6 +55,7 @@ export interface HandsontableStaticConfig {
|
||||
* Cached viyaApi collections, search and selected endpoint
|
||||
*/
|
||||
export const globals: {
|
||||
embed: boolean
|
||||
rootParam: string
|
||||
dcLib: string
|
||||
xlmaps: XLMapListItem[]
|
||||
@@ -69,6 +70,7 @@ export const globals: {
|
||||
handsontable: HandsontableStaticConfig
|
||||
[key: string]: any
|
||||
} = {
|
||||
embed: false,
|
||||
rootParam: <string>'',
|
||||
dcLib: '',
|
||||
xlmaps: [],
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<header class="app-header">
|
||||
<header class="app-header" *ngIf="!embed">
|
||||
<!-- <button
|
||||
*ngIf="
|
||||
isMainRoute('view') ||
|
||||
@@ -213,9 +213,10 @@
|
||||
</header>
|
||||
<nav
|
||||
*ngIf="
|
||||
router.url.includes('submitted') ||
|
||||
router.url.includes('approve') ||
|
||||
router.url.includes('history')
|
||||
!embed &&
|
||||
(router.url.includes('submitted') ||
|
||||
router.url.includes('approve') ||
|
||||
router.url.includes('history'))
|
||||
"
|
||||
class="subnav"
|
||||
>
|
||||
|
||||
@@ -70,6 +70,7 @@ export class AppComponent {
|
||||
|
||||
public syssite = this.appService.syssite
|
||||
public licenceState = this.licenceService.licenceState
|
||||
public embed = globals.embed
|
||||
|
||||
constructor(
|
||||
private appService: AppService,
|
||||
@@ -143,6 +144,16 @@ export class AppComponent {
|
||||
}
|
||||
})
|
||||
|
||||
const hashQuery = window.location.hash.split('?')[1]
|
||||
if (hashQuery) {
|
||||
const embedParam = new URLSearchParams(hashQuery).get('embed')
|
||||
if (embedParam !== null) {
|
||||
const isEmbed = embedParam !== 'false'
|
||||
globals.embed = isEmbed
|
||||
this.embed = isEmbed
|
||||
}
|
||||
}
|
||||
|
||||
this.subscribeToShowAbortModal()
|
||||
this.subscribeToRequestsModal()
|
||||
this.subscribeToStartupData()
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
class="card-header clr-row buttonBar headerBar clr-flex-md-row clr-justify-content-center clr-justify-content-lg-end"
|
||||
>
|
||||
<div
|
||||
*ngIf="tableTrue"
|
||||
*ngIf="tableTrue && !embed"
|
||||
class="clr-col-12 clr-col-md-3 clr-col-lg-4 backBtn"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -264,6 +264,9 @@ export class EditorComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
public badEdit = false
|
||||
public badEditCause: string | undefined
|
||||
public badEditTitle: string | undefined
|
||||
get embed() {
|
||||
return globals.embed
|
||||
}
|
||||
public tableTrue: boolean | undefined
|
||||
public saveLoading = false
|
||||
public approvers: string[] = []
|
||||
|
||||
@@ -30,7 +30,7 @@ export const freeTierConfig: LicenceState = {
|
||||
lineage_daily_limit: 3,
|
||||
tables_in_library_limit: 35,
|
||||
viewbox: true,
|
||||
fileUpload: true,
|
||||
fileUpload: false,
|
||||
editRecord: true,
|
||||
addRecord: true
|
||||
}
|
||||
|
||||
@@ -375,38 +375,30 @@ export class SpreadsheetUtil {
|
||||
fileType: string
|
||||
): Promise<ParseResult> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this.licenceState.value.submit_rows_limit !== Infinity) {
|
||||
if (!this.licenceState.value.fileUpload) {
|
||||
uploader.queue.pop()
|
||||
return reject(
|
||||
'Excel files only. To unlock CSV uploads, please contact support@datacontroller.io'
|
||||
'File uploads are not enabled for this licence. Please contact support@datacontroller.io'
|
||||
)
|
||||
}
|
||||
|
||||
if (parseParams.encoding === 'WLATIN1') {
|
||||
let reader = new FileReader()
|
||||
const self = this
|
||||
// Closure to capture the file information.
|
||||
reader.onload = (theFile: any) => {
|
||||
let encoded = iconv.decode(
|
||||
Buffer.from(theFile.target.result),
|
||||
'CP-1252'
|
||||
)
|
||||
let blob = new Blob([encoded], { type: fileType })
|
||||
let encodedFile: File = blobToFile(blob, parseParams.file.name)
|
||||
uploader.queue.pop()
|
||||
uploader.addToQueue([encodedFile])
|
||||
if (parseParams.encoding !== 'WLATIN1') return resolve({ uploader })
|
||||
|
||||
return resolve({
|
||||
uploader
|
||||
})
|
||||
}
|
||||
const reader = new FileReader()
|
||||
reader.onload = (theFile) => {
|
||||
if (!theFile.target?.result) return resolve({ uploader })
|
||||
|
||||
reader.readAsArrayBuffer(parseParams.file)
|
||||
} else {
|
||||
return resolve({
|
||||
uploader
|
||||
})
|
||||
const text = theFile.target.result as string
|
||||
const encoded = iconv.encode(text, 'CP-1252')
|
||||
const blob = new Blob([encoded], { type: fileType })
|
||||
const encodedFile: File = blobToFile(blob, parseParams.file.name)
|
||||
uploader.queue.pop()
|
||||
uploader.addToQueue([encodedFile])
|
||||
|
||||
return resolve({ uploader })
|
||||
}
|
||||
|
||||
reader.readAsText(parseParams.file)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -236,7 +236,19 @@
|
||||
<div class="admin-action">
|
||||
Download Configuration
|
||||
|
||||
<button (click)="downloadConfiguration()" class="btn btn-info btn-sm">
|
||||
<input
|
||||
type="text"
|
||||
class="clr-input libref-input"
|
||||
maxlength="8"
|
||||
[ngModel]="dcLib"
|
||||
(ngModelChange)="targetLibref = $event.toUpperCase()"
|
||||
placeholder="Target Libref"
|
||||
/>
|
||||
<button
|
||||
(click)="downloadConfiguration()"
|
||||
[disabled]="targetLibref !== dcLib && !isValidLibref(targetLibref)"
|
||||
class="btn btn-info btn-sm"
|
||||
>
|
||||
DOWNLOAD
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
.libref-input {
|
||||
width: 100px;
|
||||
margin: 0 8px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { EnvironmentInfo } from './models/environment-info.model'
|
||||
import { AppSettingsService } from '../services/app-settings.service'
|
||||
import { AppSettings } from '../models/AppSettings'
|
||||
import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse'
|
||||
import { globals } from '../_globals'
|
||||
|
||||
@Component({
|
||||
selector: 'app-system',
|
||||
@@ -39,6 +40,8 @@ export class SystemComponent implements OnInit {
|
||||
responseModal: boolean = false
|
||||
|
||||
Infinity = Infinity
|
||||
dcLib: string = globals.dcLib
|
||||
targetLibref: string = globals.dcLib
|
||||
|
||||
licenceState = this.licenceService.licenceState
|
||||
settings: AppSettings
|
||||
@@ -71,13 +74,21 @@ export class SystemComponent implements OnInit {
|
||||
this.appSettingsService.setAppSettings(this.settings)
|
||||
}
|
||||
|
||||
isValidLibref(value: string): boolean {
|
||||
return /^[A-Za-z_]\w{0,7}$/.test(value.trim())
|
||||
}
|
||||
|
||||
downloadConfiguration() {
|
||||
let sasjsConfig = this.sasService.getSasjsConfig()
|
||||
let storage = sasjsConfig.serverUrl
|
||||
let metaData = sasjsConfig.appLoc
|
||||
let path = this.sasService.getExecutionPath()
|
||||
let lib = this.targetLibref.toUpperCase().trim()
|
||||
let downUrl =
|
||||
storage + path + '/?_program=' + metaData + '/services/admin/exportconfig'
|
||||
if (lib && lib !== this.dcLib && this.isValidLibref(lib)) {
|
||||
downUrl += '&dclib=' + encodeURIComponent(lib)
|
||||
}
|
||||
window.open(downUrl)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "dcfrontend",
|
||||
"version": "7.3.0",
|
||||
"version": "7.4.1",
|
||||
"description": "Data Controller",
|
||||
"devDependencies": {
|
||||
"@saithodev/semantic-release-gitea": "^2.1.0",
|
||||
|
||||
Generated
+681
-313
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -28,7 +28,7 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@sasjs/cli": "^4.13.1",
|
||||
"@sasjs/core": "^4.60.0"
|
||||
"@sasjs/cli": "^4.15.0",
|
||||
"@sasjs/core": "^4.62.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,7 @@ NOTES:
|
||||
|
||||
One cannot use BETWEEN
|
||||
One cannot use &xx_from LE [tstamp] LE &xx_from (equivalent to above).
|
||||
Background:
|
||||
http://stackoverflow.com/questions/20005950/best-practice-for-scd-date-pairs-closing-opening-timestamps
|
||||
Background: https://stackoverflow.com/questions/20005950
|
||||
|
||||
Areas for optimisation
|
||||
- loading temporal history (currently experimental)
|
||||
@@ -220,7 +219,8 @@ Areas for optimisation
|
||||
|
||||
%local engine_type;
|
||||
%let engine_type=%mf_getengine(&base_lib);
|
||||
%if (&engine_type=REDSHIFT or &engine_type=POSTGRES) and %length(&CLOSE_VARS)>0
|
||||
%if %length(&CLOSE_VARS)>0 and (&engine_type=REDSHIFT or &engine_type=POSTGRES
|
||||
or &engine_type=SNOW or &engine_type=SASIOSNF)
|
||||
%then %do;
|
||||
%put NOTE:; %put NOTE-;%put NOTE-;%put NOTE-;
|
||||
%put NOTE- CLOSE_VARS functionality not yet supported in &engine_type;
|
||||
@@ -636,7 +636,9 @@ data work.bitemp0_append &keepvars &outds_del(drop=&md5_col )
|
||||
%dc_assignlib(WRITE,&base_lib,passthru=myAlias)
|
||||
create table work.bitemp0_base as select * from connection to myAlias(
|
||||
%end;
|
||||
%else %if &engine_type=REDSHIFT or &engine_type=POSTGRES %then %do;
|
||||
%else %if &engine_type=REDSHIFT or &engine_type=POSTGRES or &engine_type=SNOW
|
||||
or &engine_type=SASIOSNF
|
||||
%then %do;
|
||||
/* grab schema */
|
||||
%let baselib_schema=%mf_getschema(&base_lib);
|
||||
%if &baselib_schema.X ne X %then %let baselib_schema=&baselib_schema..;
|
||||
@@ -652,18 +654,24 @@ data work.bitemp0_append &keepvars &outds_del(drop=&md5_col )
|
||||
call symputx('redcnt',x,'l');
|
||||
run;
|
||||
%end;
|
||||
/* cannot persist temp tables so must create a temporary permanent table */
|
||||
%let temp_table=%mf_getuniquename(prefix=XDCTEMP);
|
||||
%let temp_table=%upcase(%mf_getuniquename(prefix=XDCTEMP));
|
||||
%if &loadtype=BITEMPORAL or &loadtype=TXTEMPORAL %then
|
||||
%let base_table=(select * from &baselib_schema.&base_dsn
|
||||
where timestamp &sqlnow < &tech_to );
|
||||
%else %let base_table=&baselib_schema.&base_dsn;
|
||||
/* make empty table first - must clone & drop extra cols as autoload is bad */
|
||||
/* make in-db empty table with PK + MD5 only */
|
||||
%dc_assignlib(WRITE,&base_lib,passthru=myAlias)
|
||||
|
||||
exec (create table &temp_table (like &baselib_schema.&base_dsn)) by myAlias;
|
||||
%if &engine_type=REDSHIFT %then %do;
|
||||
exec (alter table &temp_table alter sortkey none) by myAlias;
|
||||
%if &engine_type=SNOW or &engine_type=SASIOSNF %then %do;
|
||||
exec (create transient table &baselib_schema.&temp_table
|
||||
like &baselib_schema.&base_dsn
|
||||
) by myAlias;
|
||||
%end;
|
||||
%else %do;
|
||||
/* cannot persist temp tables so must create a temporary permanent table */
|
||||
exec (create table &temp_table (like &baselib_schema.&base_dsn)) by myAlias;
|
||||
%if &engine_type=REDSHIFT %then %do;
|
||||
exec (alter table &temp_table alter sortkey none) by myAlias;
|
||||
%end;
|
||||
%end;
|
||||
%local dropcols;
|
||||
%let dropcols=%mf_wordsinstr1butnotstr2(
|
||||
@@ -678,9 +686,12 @@ data work.bitemp0_append &keepvars &outds_del(drop=&md5_col )
|
||||
exec (alter table &temp_table add column &md5_col varchar(32);) by myAlias;
|
||||
/* create view to strip formats and avoid warns in log */
|
||||
data work.vw_bitemp0/view=work.vw_bitemp0;
|
||||
/* inherit remote length to handle byte expansion */
|
||||
if 0 then set &base_lib..&temp_table(keep=&md5_col);
|
||||
set work.bitemp0_append(keep=&pk &md5_col);
|
||||
format _all_;
|
||||
run;
|
||||
|
||||
proc append base=&base_lib..&temp_table
|
||||
%if &engine_type=REDSHIFT %then %do;
|
||||
(
|
||||
@@ -733,6 +744,7 @@ data work.bitemp0_append &keepvars &outds_del(drop=&md5_col )
|
||||
|
||||
|
||||
%if &engine_type=OLEDB or &engine_type=REDSHIFT or &engine_type=POSTGRES
|
||||
or &engine_type=SNOW or &engine_type=SASIOSNF
|
||||
%then %do;
|
||||
); proc sql; drop table &base_lib.."&temp_table"n;
|
||||
%end;
|
||||
@@ -1187,7 +1199,7 @@ run;
|
||||
%else %if (&loadtype=BITEMPORAL or &loadtype=TXTEMPORAL or &loadtype=UPDATE)
|
||||
%then %do;
|
||||
data _null_;
|
||||
putlog "&sysmacroname: &loadtype operation using &engine_type engine";
|
||||
putlog "&sysmacroname: &loadtype operation using *&engine_type* engine";
|
||||
run;
|
||||
%local flexinow;
|
||||
proc sql;
|
||||
@@ -1203,16 +1215,27 @@ run;
|
||||
%dc_assignlib(WRITE,&base_lib,passthru=myAlias)
|
||||
execute(
|
||||
%end;
|
||||
%else %if &engine_type=REDSHIFT or &engine_type=POSTGRES %then %do;
|
||||
%let innertable=%mf_getuniquename(prefix=XDCTEMP);
|
||||
%else %if &engine_type=REDSHIFT or &engine_type=POSTGRES or &engine_type=SNOW
|
||||
or &engine_type=SASIOSNF
|
||||
%then %do;
|
||||
%let innertable=%upcase(%mf_getuniquename(prefix=XDCTEMP));
|
||||
%let top_table=&baselib_schema.&base_dsn;
|
||||
%let flexinow=timestamp &SQLNOW;
|
||||
/* make empty table first - must clone & drop extra cols
|
||||
as autoload is bad */
|
||||
%dc_assignlib(WRITE,&base_lib,passthru=myAlias)
|
||||
exec (create table &innertable (like &baselib_schema.&base_dsn)) by myAlias;
|
||||
%if &engine_type=REDSHIFT %then %do;
|
||||
exec (alter table &innertable alter sortkey none) by myAlias;
|
||||
%if &engine_type=SNOW or &engine_type=SASIOSNF %then %do;
|
||||
exec (create transient table &baselib_schema.&innertable
|
||||
like &baselib_schema.&base_dsn
|
||||
) by myAlias;
|
||||
%end;
|
||||
%else %do;
|
||||
exec (create table &innertable
|
||||
(like &baselib_schema.&base_dsn)
|
||||
) by myAlias;
|
||||
%if &engine_type=REDSHIFT %then %do;
|
||||
exec (alter table &innertable alter sortkey none) by myAlias;
|
||||
%end;
|
||||
%end;
|
||||
%let dropcols=%mf_wordsinstr1butnotstr2(
|
||||
str1=%upcase(%mf_getvarlist(&basecopy))
|
||||
@@ -1240,6 +1263,7 @@ run;
|
||||
execute(
|
||||
%end;
|
||||
%else %do;
|
||||
%put Not using passthrough for *&engine_type* engine;
|
||||
%let innertable=bitemp5d_subquery;
|
||||
%let top_table=&base_lib..&base_dsn;
|
||||
%let flexinow=&now;
|
||||
@@ -1292,6 +1316,7 @@ run;
|
||||
1=1);
|
||||
|
||||
%if &engine_type=OLEDB or &engine_type=REDSHIFT or &engine_type=POSTGRES
|
||||
or &engine_type=SNOW or &engine_type=SASIOSNF
|
||||
%then %do;
|
||||
) by myAlias;
|
||||
execute (drop table &baselib_schema.&innertable) by myAlias;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
@file mpe_refreshtables.sas
|
||||
@file
|
||||
@brief Refreshes the data catalog
|
||||
@details Assumes library is already assigned.
|
||||
Usage:
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
@version 9.3
|
||||
@author 4GL Apps Ltd
|
||||
|
||||
**/
|
||||
|
||||
%macro mpe_refreshcatalogs(lib,cat=#all);
|
||||
|
||||
@@ -238,6 +238,43 @@
|
||||
"assetPaths": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "local",
|
||||
"serverUrl": "http://localhost:5000",
|
||||
"serverType": "SASJS",
|
||||
"httpsAgentOptions": {
|
||||
"rejectUnauthorized": false,
|
||||
"allowInsecureRequests": true
|
||||
},
|
||||
"appLoc": "/Public/app/dc",
|
||||
"deployConfig": {
|
||||
"deployServicePack": true,
|
||||
"deployScripts": []
|
||||
},
|
||||
"macroFolders": [
|
||||
"sasjs/targets/server/macros_server"
|
||||
],
|
||||
"programFolders": [
|
||||
"sasjs/db/datactrl"
|
||||
],
|
||||
"serviceConfig": {
|
||||
"serviceFolders": [
|
||||
"sasjs/targets/server/services_server/admin",
|
||||
"sasjs/targets/server/services_server/usernav"
|
||||
],
|
||||
"initProgram": "sasjs/utils/serviceinitserver.sas",
|
||||
"termProgram": "",
|
||||
"macroVars": {}
|
||||
},
|
||||
"streamConfig": {
|
||||
"streamWeb": true,
|
||||
"streamWebFolder": "web",
|
||||
"webSourcePath": "../client/dist",
|
||||
"streamServiceName": "DataController",
|
||||
"streamLogo": "favicon.ico",
|
||||
"assetPaths": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server-mihajlo",
|
||||
"serverUrl": "https://sas9.4gl.io",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
@li mf_existfeature.sas
|
||||
@li dc_assignlib.sas
|
||||
@li mp_ds2cards.sas
|
||||
@li mp_ds2csv.sas
|
||||
@li mp_abort.sas
|
||||
@li mp_binarycopy.sas
|
||||
@li mp_cntlout.sas
|
||||
@@ -117,10 +118,8 @@ options validvarname=upcase;
|
||||
/* cannot proc export excel if PC Files is not licensed */
|
||||
%then %do;
|
||||
%let outfile=%sysfunc(pathname(work))/&table..csv;
|
||||
PROC EXPORT DATA= staged
|
||||
OUTFILE= "&outfile"
|
||||
DBMS=csv REPLACE;
|
||||
RUN;
|
||||
/* cannot use PROC EXPORT as we need to wrap all char values in quotes */
|
||||
%mp_ds2csv(work.staged,outfile="&outfile",headerformat=NAME)
|
||||
%let ext=csv;
|
||||
%let mimetype=csv;
|
||||
%end;
|
||||
|
||||
Reference in New Issue
Block a user