mirror of
https://github.com/sasjs/core.git
synced 2026-01-06 09:00:06 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0bd88907f | ||
| 4e21772207 | |||
|
|
39f700bed2 | ||
|
|
dcb7958950 | ||
|
|
146610b5a7 | ||
|
|
9887efcf60 | ||
|
|
a2c7bdafb4 | ||
|
|
c58b5c7a52 | ||
|
|
22c7e5b4dd | ||
|
|
244171f8c4 | ||
|
|
fd765e2d68 | ||
| 840cb5ef44 | |||
| 918ce96fce | |||
| f1712c34e8 | |||
| 11ec20b472 | |||
| f42f111462 | |||
| 907725c5ba | |||
| 95b78b91e1 | |||
| e4771b9c14 | |||
| ba8190883e | |||
|
|
32dd057e83 | ||
|
|
7471bd42a4 | ||
|
|
702a4ecd3a | ||
|
|
5da97295ff | ||
|
|
dc556bdef0 | ||
|
|
111731bf35 | ||
|
|
2c526cf9dd | ||
|
|
660e02193f | ||
|
|
00b4dee86e | ||
|
|
3913825c22 | ||
|
|
0f143d603b | ||
|
|
f1d5fa2c0a | ||
|
|
a88689428f | ||
|
|
8843fa8bfc | ||
|
|
22d046cf5c | ||
|
|
29e3eb34aa | ||
|
|
1af52a6683 | ||
|
|
fc0c96dd94 | ||
|
|
b9c4882553 | ||
|
|
011b2b185c |
@@ -135,6 +135,15 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "henrik-forsell",
|
||||||
|
"name": "Henrik Forsell",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/109935936?v=4",
|
||||||
|
"profile": "https://github.com/henrik-forsell",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
|||||||
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -15,3 +15,4 @@ What code changes have been made to achieve the intent.
|
|||||||
- [ ] Code is formatted correctly (`sasjs lint`).
|
- [ ] Code is formatted correctly (`sasjs lint`).
|
||||||
- [ ] Any new functionality has been unit tested.
|
- [ ] Any new functionality has been unit tested.
|
||||||
- [ ] All unit tests are passing (`sasjs test`).
|
- [ ] All unit tests are passing (`sasjs test`).
|
||||||
|
- [ ] `all.sas` has been regenerated (`python3 build.py`)
|
||||||
|
|||||||
25
.github/vpn/config.ovpn
vendored
Normal file
25
.github/vpn/config.ovpn
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Client
|
||||||
|
client
|
||||||
|
tls-client
|
||||||
|
dev tun
|
||||||
|
# this will connect with whatever proto DNS tells us (https://community.openvpn.net/openvpn/ticket/934)
|
||||||
|
proto tcp
|
||||||
|
remote vpn.4gl.io 7494
|
||||||
|
resolv-retry infinite
|
||||||
|
cipher AES-256-CBC
|
||||||
|
auth SHA256
|
||||||
|
script-security 2
|
||||||
|
keepalive 10 120
|
||||||
|
remote-cert-tls server
|
||||||
|
|
||||||
|
# Keys
|
||||||
|
ca ca.crt
|
||||||
|
cert user.crt
|
||||||
|
key user.key
|
||||||
|
tls-auth tls.key 1
|
||||||
|
|
||||||
|
# Security
|
||||||
|
nobind
|
||||||
|
persist-key
|
||||||
|
persist-tun
|
||||||
|
verb 3
|
||||||
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Semantic Release
|
- name: Semantic Release
|
||||||
uses: cycjimmy/semantic-release-action@v2
|
uses: cycjimmy/semantic-release-action@v3
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|||||||
45
.github/workflows/run-tests.yml
vendored
45
.github/workflows/run-tests.yml
vendored
@@ -21,32 +21,49 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
|
- name: Write VPN Files
|
||||||
|
run: |
|
||||||
|
echo "$CA_CRT" > .github/vpn/ca.crt
|
||||||
|
echo "$USER_CRT" > .github/vpn/user.crt
|
||||||
|
echo "$USER_KEY" > .github/vpn/user.key
|
||||||
|
echo "$TLS_KEY" > .github/vpn/tls.key
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
CA_CRT: ${{ secrets.CA_CRT}}
|
||||||
|
USER_CRT: ${{ secrets.USER_CRT }}
|
||||||
|
USER_KEY: ${{ secrets.USER_KEY }}
|
||||||
|
TLS_KEY: ${{ secrets.TLS_KEY }}
|
||||||
|
|
||||||
|
- name: Install Open VPN
|
||||||
|
run: |
|
||||||
|
sudo apt install apt-transport-https
|
||||||
|
sudo wget https://swupdate.openvpn.net/repos/openvpn-repo-pkg-key.pub
|
||||||
|
sudo apt-key add openvpn-repo-pkg-key.pub
|
||||||
|
sudo wget -O /etc/apt/sources.list.d/openvpn3.list https://swupdate.openvpn.net/community/openvpn3/repos/openvpn3-jammy.list
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install openvpn3=17~betaUb22042+jammy
|
||||||
|
- name: Start Open VPN 3
|
||||||
|
run: openvpn3 session-start --config .github/vpn/config.ovpn
|
||||||
- name: Install Doxygen
|
- name: Install Doxygen
|
||||||
run: sudo apt-get install doxygen
|
run: sudo apt-get install doxygen
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
- name: Check code style
|
- name: Check code style (aborts if errors found)
|
||||||
run: npm run lint
|
run: npx sasjs lint
|
||||||
|
|
||||||
- name: Add client
|
- name: Add client
|
||||||
run: echo "CLIENT=${{secrets.CLIENT}}"> .env.viya
|
run: echo "CLIENT=${{secrets.SAS9_4GL_IO_CLIENT}}"> .env.server
|
||||||
|
|
||||||
- name: Add secret
|
|
||||||
run: echo "SECRET=${{secrets.SECRET}}" >> .env.viya
|
|
||||||
|
|
||||||
- name: Add access token
|
- name: Add access token
|
||||||
run: echo "ACCESS_TOKEN=${{secrets.ACCESS_TOKEN}}" >> .env.viya
|
run: echo "ACCESS_TOKEN=${{secrets.SAS9_4GL_IO_ACCESS_TOKEN}}" >> .env.server
|
||||||
|
|
||||||
- name: Add refresh token
|
- name: Build & Deploy Project to SAS server
|
||||||
run: echo "REFRESH_TOKEN=${{secrets.REFRESH_TOKEN}}" >> .env.viya
|
run: npx sasjs cbd -t server
|
||||||
|
|
||||||
- name: Build Project
|
- name: Run all tests
|
||||||
run: npm run build
|
run: npx sasjs test -t server
|
||||||
|
|
||||||
- name: Run SASjs tests
|
|
||||||
run: npm run test
|
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
CLIENT: ${{secrets.CLIENT}}
|
CLIENT: ${{secrets.CLIENT}}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"hasDoxygenHeader": true,
|
"hasDoxygenHeader": true,
|
||||||
"hasMacroNameInMend": true,
|
"hasMacroNameInMend": true,
|
||||||
"hasMacroParentheses": true,
|
"hasMacroParentheses": true,
|
||||||
|
"lineEndings": "lf",
|
||||||
"noGremlins": true,
|
"noGremlins": true,
|
||||||
"noNestedMacros": false,
|
"noNestedMacros": false,
|
||||||
"noSpacesInFileNames": true,
|
"noSpacesInFileNames": true,
|
||||||
|
|||||||
39
README.md
39
README.md
@@ -2,8 +2,6 @@
|
|||||||
[![npm package][npm-image]][npm-url]
|
[![npm package][npm-image]][npm-url]
|
||||||
[![Github Workflow][githubworkflow-image]][githubworkflow-url]
|
[![Github Workflow][githubworkflow-image]][githubworkflow-url]
|
||||||

|

|
||||||

|
|
||||||
[](/LICENSE)
|
|
||||||

|

|
||||||
[](https://github.com/sasjs/core/issues?q=is%3Aissue+is%3Aclosed)
|
[](https://github.com/sasjs/core/issues?q=is%3Aissue+is%3Aclosed)
|
||||||
[](https://github.com/sasjs/core/issues)
|
[](https://github.com/sasjs/core/issues)
|
||||||
@@ -248,7 +246,7 @@ The following repositories are also worth checking out:
|
|||||||
|
|
||||||
## Contributors ✨
|
## Contributors ✨
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||||
[](#contributors-)
|
[](#contributors-)
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||||
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
||||||
|
|
||||||
@@ -256,22 +254,25 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||||||
<!-- prettier-ignore-start -->
|
<!-- prettier-ignore-start -->
|
||||||
<!-- markdownlint-disable -->
|
<!-- markdownlint-disable -->
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tbody>
|
||||||
<td align="center"><a href="https://github.com/allanbowe"><img src="https://avatars.githubusercontent.com/u/4420615?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Allan Bowe</b></sub></a><br /><a href="#business-allanbowe" title="Business development">💼</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Code">💻</a> <a href="#content-allanbowe" title="Content">🖋</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Documentation">📖</a> <a href="#infra-allanbowe" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-allanbowe" title="Maintenance">🚧</a> <a href="#mentoring-allanbowe" title="Mentoring">🧑🏫</a> <a href="#question-allanbowe" title="Answering Questions">💬</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3Aallanbowe" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Tests">⚠️</a></td>
|
<tr>
|
||||||
<td align="center"><a href="https://github.com/rafgag"><img src="https://avatars.githubusercontent.com/u/69139928?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rafgag</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=rafgag" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/allanbowe"><img src="https://avatars.githubusercontent.com/u/4420615?v=4?s=100" width="100px;" alt="Allan Bowe"/><br /><sub><b>Allan Bowe</b></sub></a><br /><a href="#business-allanbowe" title="Business development">💼</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Code">💻</a> <a href="#content-allanbowe" title="Content">🖋</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Documentation">📖</a> <a href="#infra-allanbowe" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-allanbowe" title="Maintenance">🚧</a> <a href="#mentoring-allanbowe" title="Mentoring">🧑🏫</a> <a href="#question-allanbowe" title="Answering Questions">💬</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3Aallanbowe" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Tests">⚠️</a></td>
|
||||||
<td align="center"><a href="https://github.com/tmoody"><img src="https://avatars.githubusercontent.com/u/79837106?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Trevor Moody</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=tmoody" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rafgag"><img src="https://avatars.githubusercontent.com/u/69139928?v=4?s=100" width="100px;" alt="rafgag"/><br /><sub><b>rafgag</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=rafgag" title="Code">💻</a></td>
|
||||||
<td align="center"><a href="https://krishna-acondy.io/"><img src="https://avatars.githubusercontent.com/u/2980428?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Krishna Acondy</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=krishna-acondy" title="Code">💻</a> <a href="#infra-krishna-acondy" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#blog-krishna-acondy" title="Blogposts">📝</a> <a href="#content-krishna-acondy" title="Content">🖋</a> <a href="#ideas-krishna-acondy" title="Ideas, Planning, & Feedback">🤔</a> <a href="#video-krishna-acondy" title="Videos">📹</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tmoody"><img src="https://avatars.githubusercontent.com/u/79837106?v=4?s=100" width="100px;" alt="Trevor Moody"/><br /><sub><b>Trevor Moody</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=tmoody" title="Code">💻</a></td>
|
||||||
<td align="center"><a href="https://github.com/saadjutt01"><img src="https://avatars.githubusercontent.com/u/8914650?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Muhammad Saad </b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=saadjutt01" title="Code">💻</a> <a href="#ideas-saadjutt01" title="Ideas, Planning, & Feedback">🤔</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://krishna-acondy.io/"><img src="https://avatars.githubusercontent.com/u/2980428?v=4?s=100" width="100px;" alt="Krishna Acondy"/><br /><sub><b>Krishna Acondy</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=krishna-acondy" title="Code">💻</a> <a href="#infra-krishna-acondy" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#blog-krishna-acondy" title="Blogposts">📝</a> <a href="#content-krishna-acondy" title="Content">🖋</a> <a href="#ideas-krishna-acondy" title="Ideas, Planning, & Feedback">🤔</a> <a href="#video-krishna-acondy" title="Videos">📹</a></td>
|
||||||
<td align="center"><a href="https://www.erudicat.com/"><img src="https://avatars.githubusercontent.com/u/25773492?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yury Shkoda</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=YuryShkoda" title="Code">💻</a> <a href="#infra-YuryShkoda" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#video-YuryShkoda" title="Videos">📹</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/saadjutt01"><img src="https://avatars.githubusercontent.com/u/8914650?v=4?s=100" width="100px;" alt="Muhammad Saad "/><br /><sub><b>Muhammad Saad </b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=saadjutt01" title="Code">💻</a> <a href="#ideas-saadjutt01" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||||
<td align="center"><a href="https://github.com/medjedovicm"><img src="https://avatars.githubusercontent.com/u/18329105?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mihajlo Medjedovic</b></sub></a><br /><a href="#infra-medjedovicm" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://www.erudicat.com/"><img src="https://avatars.githubusercontent.com/u/25773492?v=4?s=100" width="100px;" alt="Yury Shkoda"/><br /><sub><b>Yury Shkoda</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=YuryShkoda" title="Code">💻</a> <a href="#infra-YuryShkoda" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#video-YuryShkoda" title="Videos">📹</a></td>
|
||||||
</tr>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/medjedovicm"><img src="https://avatars.githubusercontent.com/u/18329105?v=4?s=100" width="100px;" alt="Mihajlo Medjedovic"/><br /><sub><b>Mihajlo Medjedovic</b></sub></a><br /><a href="#infra-medjedovicm" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||||
<tr>
|
</tr>
|
||||||
<td align="center"><a href="https://github.com/kkchandok"><img src="https://avatars.githubusercontent.com/u/46090627?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kkchandok</b></sub></a><br /><a href="#ideas-kkchandok" title="Ideas, Planning, & Feedback">🤔</a></td>
|
<tr>
|
||||||
<td align="center"><a href="https://github.com/VladislavParhomchik"><img src="https://avatars.githubusercontent.com/u/83717836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vladislav Parhomchik</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=VladislavParhomchik" title="Tests">⚠️</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3AVladislavParhomchik" title="Reviewed Pull Requests">👀</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kkchandok"><img src="https://avatars.githubusercontent.com/u/46090627?v=4?s=100" width="100px;" alt="kkchandok"/><br /><sub><b>kkchandok</b></sub></a><br /><a href="#ideas-kkchandok" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||||
<td align="center"><a href="https://github.com/vznesh"><img src="https://avatars.githubusercontent.com/u/28916792?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vignesh T.</b></sub></a><br /><a href="https://github.com/sasjs/core/issues?q=author%3Avznesh" title="Bug reports">🐛</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VladislavParhomchik"><img src="https://avatars.githubusercontent.com/u/83717836?v=4?s=100" width="100px;" alt="Vladislav Parhomchik"/><br /><sub><b>Vladislav Parhomchik</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=VladislavParhomchik" title="Tests">⚠️</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3AVladislavParhomchik" title="Reviewed Pull Requests">👀</a></td>
|
||||||
<td align="center"><a href="https://github.com/yabwon"><img src="https://avatars.githubusercontent.com/u/9314894?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bart Jablonski</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=yabwon" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vznesh"><img src="https://avatars.githubusercontent.com/u/28916792?v=4?s=100" width="100px;" alt="Vignesh T."/><br /><sub><b>Vignesh T.</b></sub></a><br /><a href="https://github.com/sasjs/core/issues?q=author%3Avznesh" title="Bug reports">🐛</a></td>
|
||||||
<td align="center"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=eltociear" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yabwon"><img src="https://avatars.githubusercontent.com/u/9314894?v=4?s=100" width="100px;" alt="Bart Jablonski"/><br /><sub><b>Bart Jablonski</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=yabwon" title="Code">💻</a></td>
|
||||||
</tr>
|
<td align="center" valign="top" width="14.28%"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt="Ikko Ashimine"/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=eltociear" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/henrik-forsell"><img src="https://avatars.githubusercontent.com/u/109935936?v=4?s=100" width="100px;" alt="Henrik Forsell"/><br /><sub><b>Henrik Forsell</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=henrik-forsell" title="Documentation">📖</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<!-- markdownlint-restore -->
|
<!-- markdownlint-restore -->
|
||||||
|
|||||||
273
all.sas
273
all.sas
@@ -30,7 +30,7 @@ options noquotelenmax;
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
%macro mf_abort(mac=mf_abort.sas, msg=, iftrue=%str(1=1)
|
%macro mf_abort(mac=mf_abort.sas, msg=, iftrue=%str(1=1)
|
||||||
)/*/STORE SOURCE*/;
|
)/des='ungraceful abort' /*STORE SOURCE*/;
|
||||||
|
|
||||||
%if not(%eval(%unquote(&iftrue))) %then %return;
|
%if not(%eval(%unquote(&iftrue))) %then %return;
|
||||||
|
|
||||||
@@ -42,7 +42,8 @@ options noquotelenmax;
|
|||||||
|
|
||||||
%mend mf_abort;
|
%mend mf_abort;
|
||||||
|
|
||||||
/** @endcond *//**
|
/** @endcond */
|
||||||
|
/**
|
||||||
@file
|
@file
|
||||||
@brief de-duplicates a macro string
|
@brief de-duplicates a macro string
|
||||||
@details Removes all duplicates from a string of words. A delimeter can be
|
@details Removes all duplicates from a string of words. A delimeter can be
|
||||||
@@ -311,13 +312,17 @@ https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md#functionex
|
|||||||
%local dsid rc;
|
%local dsid rc;
|
||||||
%let dsid=%sysfunc(open(&libds,is));
|
%let dsid=%sysfunc(open(&libds,is));
|
||||||
|
|
||||||
%if &dsid=0 or %length(&var)=0 %then %do;
|
%if &dsid=0 %then %do;
|
||||||
%put %sysfunc(sysmsg());
|
%put %sysfunc(sysmsg());
|
||||||
0
|
0
|
||||||
|
%end;
|
||||||
|
%else %if %length(&var)=0 %then %do;
|
||||||
|
0
|
||||||
|
%let rc=%sysfunc(close(&dsid));
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
%sysfunc(varnum(&dsid,&var))
|
%sysfunc(varnum(&dsid,&var))
|
||||||
%let rc=%sysfunc(close(&dsid));
|
%let rc=%sysfunc(close(&dsid));
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%mend mf_existvar;
|
%mend mf_existvar;
|
||||||
@@ -2653,6 +2658,100 @@ and %superq(SYSPROCESSNAME) ne %str(Compute Server)
|
|||||||
%mend mp_abort;
|
%mend mp_abort;
|
||||||
|
|
||||||
/** @endcond */
|
/** @endcond */
|
||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Apply leading blanks to align numbers vertically in a char variable
|
||||||
|
@details This is particularly useful when storing numbers (as character) that
|
||||||
|
need to be sorted.
|
||||||
|
|
||||||
|
It works by splitting the number left and right of the decimal place, and
|
||||||
|
aligning it accordingly. A temporary variable is created as part of this
|
||||||
|
process (which is automatically dropped)
|
||||||
|
|
||||||
|
The macro can be used only in data step, eg as follows:
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
length myvar $50;
|
||||||
|
do i=1 to 1000 by 50;
|
||||||
|
if mod(i,2)=0 then j=ranuni(0)*i*100;
|
||||||
|
else j=i*100;
|
||||||
|
|
||||||
|
%mp_aligndecimal(myvar,width=7)
|
||||||
|
|
||||||
|
leading_spaces=length(myvar)-length(cats(myvar));
|
||||||
|
putlog +leading_spaces myvar;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
The generated code will look something like this:
|
||||||
|
|
||||||
|
length aligndp4e49996 $7;
|
||||||
|
if index(myvar,'.') then do;
|
||||||
|
aligndp4e49996=cats(scan(myvar,1,'.'));
|
||||||
|
aligndp4e49996=right(aligndp4e49996);
|
||||||
|
myvar=aligndp4e49996!!'.'!!cats(scan(myvar,2,'.'));
|
||||||
|
end;
|
||||||
|
else do;
|
||||||
|
aligndp4e49996=myvar;
|
||||||
|
aligndp4e49996=right(aligndp4e49996);
|
||||||
|
myvar=aligndp4e49996;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Results (myvar variable):
|
||||||
|
|
||||||
|
0.7683559324
|
||||||
|
122.8232796
|
||||||
|
99419.50552
|
||||||
|
42938.5143414
|
||||||
|
763.3799189
|
||||||
|
15170.606073
|
||||||
|
15083.285773
|
||||||
|
85443.198707
|
||||||
|
2022999.2251
|
||||||
|
12038.658867
|
||||||
|
1350582.6734
|
||||||
|
52777.258221
|
||||||
|
11723.347628
|
||||||
|
33101.268376
|
||||||
|
6181622.8603
|
||||||
|
7390614.0669
|
||||||
|
73384.537893
|
||||||
|
1788362.1016
|
||||||
|
2774586.2219
|
||||||
|
7998580.8415
|
||||||
|
|
||||||
|
|
||||||
|
@param var The (data step) variable to create
|
||||||
|
@param width= (8) The number of characters BEFORE the decimal point
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquename.sas
|
||||||
|
|
||||||
|
<h4> Related Programs </h4>
|
||||||
|
@li mp_aligndecimal.test.sas
|
||||||
|
|
||||||
|
@version 9.2
|
||||||
|
@author Allan Bowe
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_aligndecimal(var,width=8);
|
||||||
|
|
||||||
|
%local tmpvar;
|
||||||
|
%let tmpvar=%mf_getuniquename(prefix=aligndp);
|
||||||
|
length &tmpvar $&width;
|
||||||
|
if index(&var,'.') then do;
|
||||||
|
&tmpvar=cats(scan(&var,1,'.'));
|
||||||
|
&tmpvar=right(&tmpvar);
|
||||||
|
&var=&tmpvar!!'.'!!cats(scan(&var,2,'.'));
|
||||||
|
end;
|
||||||
|
else do;
|
||||||
|
&tmpvar=cats(&var);
|
||||||
|
&tmpvar=right(&tmpvar);
|
||||||
|
&var=&tmpvar;
|
||||||
|
end;
|
||||||
|
drop &tmpvar;
|
||||||
|
|
||||||
|
%mend mp_aligndecimal;
|
||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Append (concatenate) two or more files.
|
@brief Append (concatenate) two or more files.
|
||||||
@@ -2913,7 +3012,7 @@ run;
|
|||||||
results. If it does not exist, it will be created, with the following format:
|
results. If it does not exist, it will be created, with the following format:
|
||||||
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|User Provided description|PASS|Column &inds contained ALL columns|
|
|User Provided description|PASS|Dataset &inds contained ALL columns|
|
||||||
|
|
||||||
@version 9.2
|
@version 9.2
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
@@ -2987,7 +3086,7 @@ run;
|
|||||||
results. If it does not exist, it will be created, with the following format:
|
results. If it does not exist, it will be created, with the following format:
|
||||||
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|User Provided description|PASS|Column &inds contained ALL columns|
|
|User Provided description|PASS|Dataset &inds contained ALL columns|
|
||||||
|
|
||||||
|
|
||||||
<h4> Related Macros </h4>
|
<h4> Related Macros </h4>
|
||||||
@@ -3132,6 +3231,7 @@ run;
|
|||||||
@param [in] test= (ALLVALS) The test to apply. Valid values are:
|
@param [in] test= (ALLVALS) The test to apply. Valid values are:
|
||||||
@li ALLVALS - Test is a PASS if ALL values have a match in checkvals
|
@li ALLVALS - Test is a PASS if ALL values have a match in checkvals
|
||||||
@li ANYVAL - Test is a PASS if at least 1 value has a match in checkvals
|
@li ANYVAL - Test is a PASS if at least 1 value has a match in checkvals
|
||||||
|
@li NOVAL - Test is a PASS if there are NO matches in checkvals
|
||||||
@param [out] outds= (work.test_results) The output dataset to contain the
|
@param [out] outds= (work.test_results) The output dataset to contain the
|
||||||
results. If it does not exist, it will be created, with the following format:
|
results. If it does not exist, it will be created, with the following format:
|
||||||
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
||||||
@@ -3187,7 +3287,7 @@ run;
|
|||||||
|
|
||||||
%let test=%upcase(&test);
|
%let test=%upcase(&test);
|
||||||
|
|
||||||
%if &test ne ALLVALS and &test ne ANYVAL %then %do;
|
%if &test ne ALLVALS and &test ne ANYVAL and &test ne NOVAL %then %do;
|
||||||
%mp_abort(
|
%mp_abort(
|
||||||
mac=&sysmacroname,
|
mac=&sysmacroname,
|
||||||
msg=%str(Invalid test - &test)
|
msg=%str(Invalid test - &test)
|
||||||
@@ -3198,12 +3298,12 @@ run;
|
|||||||
%let result=-1;
|
%let result=-1;
|
||||||
%let orig=-1;
|
%let orig=-1;
|
||||||
proc sql noprint;
|
proc sql noprint;
|
||||||
select count(*) into: result
|
select count(*) into: result trimmed
|
||||||
from &lib..&ds
|
from &lib..&ds
|
||||||
where &col not in (
|
where &col not in (
|
||||||
select &ccol from &clib..&cds
|
select &ccol from &clib..&cds
|
||||||
);
|
);
|
||||||
select count(*) into: orig from &lib..&ds;
|
select count(*) into: orig trimmed from &lib..&ds;
|
||||||
quit;
|
quit;
|
||||||
|
|
||||||
%local notfound tmp1 tmp2;
|
%local notfound tmp1 tmp2;
|
||||||
@@ -3235,7 +3335,7 @@ run;
|
|||||||
length test_description $256 test_result $4 test_comments $256;
|
length test_description $256 test_result $4 test_comments $256;
|
||||||
test_description=symget('desc');
|
test_description=symget('desc');
|
||||||
test_result='FAIL';
|
test_result='FAIL';
|
||||||
test_comments="&sysmacroname: &lib..&ds..&col has &result values "
|
test_comments="&sysmacroname: &lib..&ds..&col has &result/&orig values "
|
||||||
!!"not in &clib..&cds..&ccol.. First 10 vals:"!!symget('notfound');
|
!!"not in &clib..&cds..&ccol.. First 10 vals:"!!symget('notfound');
|
||||||
%if &test=ANYVAL %then %do;
|
%if &test=ANYVAL %then %do;
|
||||||
if &result < &orig then test_result='PASS';
|
if &result < &orig then test_result='PASS';
|
||||||
@@ -3243,6 +3343,9 @@ run;
|
|||||||
%else %if &test=ALLVALS %then %do;
|
%else %if &test=ALLVALS %then %do;
|
||||||
if &result=0 then test_result='PASS';
|
if &result=0 then test_result='PASS';
|
||||||
%end;
|
%end;
|
||||||
|
%else %if &test=NOVAL %then %do;
|
||||||
|
if &result=&orig then test_result='PASS';
|
||||||
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
test_comments="&sysmacroname: Unsatisfied test condition - &test";
|
test_comments="&sysmacroname: Unsatisfied test condition - &test";
|
||||||
%end;
|
%end;
|
||||||
@@ -4018,6 +4121,7 @@ run;
|
|||||||
|
|
||||||
<h4> Related Macros </h4>
|
<h4> Related Macros </h4>
|
||||||
@li mf_getvarformat.sas
|
@li mf_getvarformat.sas
|
||||||
|
@li mp_aligndecimal.sas
|
||||||
@li mp_getformats.sas
|
@li mp_getformats.sas
|
||||||
@li mp_loadformat.sas
|
@li mp_loadformat.sas
|
||||||
@li mp_ds2fmtds.sas
|
@li mp_ds2fmtds.sas
|
||||||
@@ -4059,13 +4163,13 @@ run;
|
|||||||
data &cntlout;
|
data &cntlout;
|
||||||
if 0 then set &ddlds;
|
if 0 then set &ddlds;
|
||||||
set &cntlds;
|
set &cntlds;
|
||||||
if type="N" then do;
|
if type in ("I","N") then do; /* numeric (in)format */
|
||||||
start=cats(start);
|
%mp_aligndecimal(start,width=16)
|
||||||
end=cats(end);
|
%mp_aligndecimal(end,width=16)
|
||||||
end;
|
end;
|
||||||
run;
|
run;
|
||||||
proc sort;
|
proc sort;
|
||||||
by fmtname start;
|
by type fmtname start;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
proc sql;
|
proc sql;
|
||||||
@@ -10025,6 +10129,7 @@ select distinct lowcase(memname)
|
|||||||
<h4> Related Macros </h4>
|
<h4> Related Macros </h4>
|
||||||
@li mddl_dc_difftable.sas
|
@li mddl_dc_difftable.sas
|
||||||
@li mddl_dc_locktable.sas
|
@li mddl_dc_locktable.sas
|
||||||
|
@li mp_aligndecimal.sas
|
||||||
@li mp_loadformat.test.sas
|
@li mp_loadformat.test.sas
|
||||||
@li mp_lockanytable.sas
|
@li mp_lockanytable.sas
|
||||||
@li mp_stackdiffs.sas
|
@li mp_stackdiffs.sas
|
||||||
@@ -10114,7 +10219,16 @@ run;
|
|||||||
* First, extract only relevant formats from the catalog
|
* First, extract only relevant formats from the catalog
|
||||||
*/
|
*/
|
||||||
proc sql noprint;
|
proc sql noprint;
|
||||||
select distinct upcase(fmtname) into: fmtlist separated by ' ' from &libds;
|
select distinct
|
||||||
|
case
|
||||||
|
when type='N' then upcase(fmtname)
|
||||||
|
when type='C' then cats('$',upcase(fmtname))
|
||||||
|
when type='I' then cats('@',upcase(fmtname))
|
||||||
|
when type='J' then cats('@$',upcase(fmtname))
|
||||||
|
else "&sysmacroname:UNHANDLED"
|
||||||
|
end
|
||||||
|
into: fmtlist separated by ' '
|
||||||
|
from &libds;
|
||||||
|
|
||||||
%mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts)
|
%mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts)
|
||||||
|
|
||||||
@@ -10126,16 +10240,24 @@ select distinct upcase(fmtname) into: fmtlist separated by ' ' from &libds;
|
|||||||
data &inlibds;
|
data &inlibds;
|
||||||
length &delete_col $3;
|
length &delete_col $3;
|
||||||
if 0 then set &template;
|
if 0 then set &template;
|
||||||
|
length start end $10000;
|
||||||
set &libds;
|
set &libds;
|
||||||
if &delete_col='' then &delete_col='No';
|
if &delete_col='' then &delete_col='No';
|
||||||
fmtname=upcase(fmtname);
|
fmtname=upcase(fmtname);
|
||||||
|
type=upcase(type);
|
||||||
if missing(type) then do;
|
if missing(type) then do;
|
||||||
if substr(fmtname,1,1)='$' then type='C';
|
if substr(fmtname,1,1)='@' then do;
|
||||||
else type='N';
|
if substr(fmtname,2,1)='$' then type='J';
|
||||||
|
else type='I';
|
||||||
|
end;
|
||||||
|
else do;
|
||||||
|
if substr(fmtname,1,1)='$' then type='C';
|
||||||
|
else type='N';
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
if type='N' then do;
|
if type in ('N','I') then do;
|
||||||
start=cats(start);
|
%mp_aligndecimal(start,width=16)
|
||||||
end=cats(end);
|
%mp_aligndecimal(end,width=16)
|
||||||
end;
|
end;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
@@ -10149,9 +10271,10 @@ create table &outds_add(drop=&delete_col) as
|
|||||||
left join &base_fmts b
|
left join &base_fmts b
|
||||||
on a.fmtname=b.fmtname
|
on a.fmtname=b.fmtname
|
||||||
and a.start=b.start
|
and a.start=b.start
|
||||||
|
and a.type=b.type
|
||||||
where b.fmtname is null
|
where b.fmtname is null
|
||||||
and upcase(a.&delete_col) ne "YES"
|
and upcase(a.&delete_col) ne "YES"
|
||||||
order by fmtname, start;;
|
order by type, fmtname, start;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identify deleted records
|
* Identify deleted records
|
||||||
@@ -10162,8 +10285,9 @@ create table &outds_del(drop=&delete_col) as
|
|||||||
inner join &base_fmts b
|
inner join &base_fmts b
|
||||||
on a.fmtname=b.fmtname
|
on a.fmtname=b.fmtname
|
||||||
and a.start=b.start
|
and a.start=b.start
|
||||||
|
and a.type=b.type
|
||||||
where upcase(a.&delete_col)="YES"
|
where upcase(a.&delete_col)="YES"
|
||||||
order by fmtname, start;
|
order by type, fmtname, start;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identify modified records
|
* Identify modified records
|
||||||
@@ -10174,8 +10298,9 @@ create table &outds_mod (drop=&delete_col) as
|
|||||||
inner join &base_fmts b
|
inner join &base_fmts b
|
||||||
on a.fmtname=b.fmtname
|
on a.fmtname=b.fmtname
|
||||||
and a.start=b.start
|
and a.start=b.start
|
||||||
|
and a.type=b.type
|
||||||
where upcase(a.&delete_col) ne "YES"
|
where upcase(a.&delete_col) ne "YES"
|
||||||
order by fmtname, start;
|
order by type, fmtname, start;
|
||||||
|
|
||||||
options ibufsize=&ibufsize;
|
options ibufsize=&ibufsize;
|
||||||
|
|
||||||
@@ -10192,13 +10317,13 @@ options ibufsize=&ibufsize;
|
|||||||
&outds_add(in=add)
|
&outds_add(in=add)
|
||||||
&outds_del(in=del);
|
&outds_del(in=del);
|
||||||
if not del and not mod;
|
if not del and not mod;
|
||||||
by fmtname start;
|
by type fmtname start;
|
||||||
run;
|
run;
|
||||||
data &stagedata;
|
data &stagedata;
|
||||||
set &ds1 &outds_mod;
|
set &ds1 &outds_mod;
|
||||||
run;
|
run;
|
||||||
proc sort;
|
proc sort;
|
||||||
by fmtname start;
|
by type fmtname start;
|
||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
/* mp abort needs to run outside of conditional blocks */
|
/* mp abort needs to run outside of conditional blocks */
|
||||||
@@ -10246,7 +10371,7 @@ options ibufsize=&ibufsize;
|
|||||||
|
|
||||||
%mp_storediffs(&libcat-FC
|
%mp_storediffs(&libcat-FC
|
||||||
,&base_fmts
|
,&base_fmts
|
||||||
,FMTNAME START
|
,TYPE FMTNAME START
|
||||||
,delds=&outds_del
|
,delds=&outds_del
|
||||||
,modds=&outds_mod
|
,modds=&outds_mod
|
||||||
,appds=&outds_add
|
,appds=&outds_add
|
||||||
@@ -10450,7 +10575,7 @@ run;
|
|||||||
data _null_;
|
data _null_;
|
||||||
putlog 'NOTE-' / 'NOTE-';
|
putlog 'NOTE-' / 'NOTE-';
|
||||||
putlog "NOTE- &sysmacroname: table locked, waiting "@;
|
putlog "NOTE- &sysmacroname: table locked, waiting "@;
|
||||||
putlog "%sysfunc(sleep(&loop_inc)) seconds.. ";
|
putlog "%sysfunc(sleep(&loop_secs)) seconds.. ";
|
||||||
putlog "NOTE- (iteration &x of &loops)";
|
putlog "NOTE- (iteration &x of &loops)";
|
||||||
putlog 'NOTE-' / 'NOTE-';
|
putlog 'NOTE-' / 'NOTE-';
|
||||||
run;
|
run;
|
||||||
@@ -10483,7 +10608,10 @@ run;
|
|||||||
where LOCK_LIB ="&lib" and LOCK_DS="&ds";
|
where LOCK_LIB ="&lib" and LOCK_DS="&ds";
|
||||||
quit;
|
quit;
|
||||||
%if &syscc>0 %then %put syscc=&syscc sqlrc=&sqlrc;
|
%if &syscc>0 %then %put syscc=&syscc sqlrc=&sqlrc;
|
||||||
%if &status=LOCKED %then %do;
|
%if &sqlobs=0 %then %do;
|
||||||
|
%put %str(WAR)NING: &lib..&ds has never been locked!;
|
||||||
|
%end;
|
||||||
|
%else %if &status=LOCKED %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
putlog "&sysmacroname: unlocking &lib..&ds:";
|
putlog "&sysmacroname: unlocking &lib..&ds:";
|
||||||
run;
|
run;
|
||||||
@@ -13948,14 +14076,20 @@ ods package close;
|
|||||||
|
|
||||||
proc sql;
|
proc sql;
|
||||||
create table &libds(
|
create table &libds(
|
||||||
FMTNAME char(32) label='Format name'
|
TYPE char(1) label='Type of format'
|
||||||
|
,FMTNAME char(32) label='Format name'
|
||||||
/*
|
/*
|
||||||
to accommodate larger START values, mp_loadformat.sas will need the
|
to accommodate larger START values, mp_loadformat.sas will need the
|
||||||
SQL dependency removed (proc sql needs to accommodate 3 index values in
|
SQL dependency removed (proc sql needs to accommodate 3 index values in
|
||||||
a 32767 ibufsize limit)
|
a 32767 ibufsize limit)
|
||||||
*/
|
*/
|
||||||
,START char(10000) label='Starting value for format'
|
,START char(10000) label='Starting value for format'
|
||||||
,END char(32767) label='Ending value for format'
|
/*
|
||||||
|
Keep lengths of START and END the same to avoid this err:
|
||||||
|
"Start is greater than end: -<."
|
||||||
|
Similar usage note: https://support.sas.com/kb/69/330.html
|
||||||
|
*/
|
||||||
|
,END char(10000) label='Ending value for format'
|
||||||
,LABEL char(32767) label='Format value label'
|
,LABEL char(32767) label='Format value label'
|
||||||
,MIN num length=3 label='Minimum length'
|
,MIN num length=3 label='Minimum length'
|
||||||
,MAX num length=3 label='Maximum length'
|
,MAX num length=3 label='Maximum length'
|
||||||
@@ -13966,7 +14100,6 @@ create table &libds(
|
|||||||
,MULT num label='Multiplier'
|
,MULT num label='Multiplier'
|
||||||
,FILL char(1) label='Fill character'
|
,FILL char(1) label='Fill character'
|
||||||
,NOEDIT num length=3 label='Is picture string noedit?'
|
,NOEDIT num length=3 label='Is picture string noedit?'
|
||||||
,TYPE char(1) label='Type of format'
|
|
||||||
,SEXCL char(1) label='Start exclusion'
|
,SEXCL char(1) label='Start exclusion'
|
||||||
,EEXCL char(1) label='End exclusion'
|
,EEXCL char(1) label='End exclusion'
|
||||||
,HLO char(13) label='Additional information'
|
,HLO char(13) label='Additional information'
|
||||||
@@ -14060,7 +14193,8 @@ run;
|
|||||||
filename __us2grp temp;
|
filename __us2grp temp;
|
||||||
|
|
||||||
proc metadata in= "<UpdateMetadata><Reposid>$METAREPOSITORY</Reposid><Metadata>
|
proc metadata in= "<UpdateMetadata><Reposid>$METAREPOSITORY</Reposid><Metadata>
|
||||||
<Person Id='&uuri'><IdentityGroups><IdentityGroup ObjRef='&guri' />
|
<Person Id='%nrstr(&uuri)'>
|
||||||
|
<IdentityGroups><IdentityGroup ObjRef='%nrstr(&guri)' />
|
||||||
</IdentityGroups></Person></Metadata>
|
</IdentityGroups></Person></Metadata>
|
||||||
<NS>SAS</NS><Flags>268435456</Flags></UpdateMetadata>"
|
<NS>SAS</NS><Flags>268435456</Flags></UpdateMetadata>"
|
||||||
out=__us2grp verbose;
|
out=__us2grp verbose;
|
||||||
@@ -14077,7 +14211,8 @@ run;
|
|||||||
|
|
||||||
filename __us2grp clear;
|
filename __us2grp clear;
|
||||||
|
|
||||||
%mend mm_adduser2group;/**
|
%mend mm_adduser2group;
|
||||||
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Assigns library directly using details from metadata
|
@brief Assigns library directly using details from metadata
|
||||||
@details Queries metadata to get the libname definition then allocates the
|
@details Queries metadata to get the libname definition then allocates the
|
||||||
@@ -16540,9 +16675,11 @@ data _null_;
|
|||||||
put ' ';
|
put ' ';
|
||||||
put '%mend mm_webout; ';
|
put '%mend mm_webout; ';
|
||||||
/* WEBOUT END */
|
/* WEBOUT END */
|
||||||
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO);';
|
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO';
|
||||||
|
put ' ,maxobs=MAX';
|
||||||
|
put ');';
|
||||||
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
|
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
|
||||||
put ' ,showmeta=&showmeta';
|
put ' ,showmeta=&showmeta,maxobs=&maxobs';
|
||||||
put ' )';
|
put ' )';
|
||||||
put '%mend;';
|
put '%mend;';
|
||||||
run;
|
run;
|
||||||
@@ -22105,8 +22242,9 @@ options &optval;
|
|||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_getuniquefileref.sas
|
@li mf_getuniquefileref.sas
|
||||||
@li mf_getuniquelibref.sas
|
@li mf_getuniquename.sas
|
||||||
@li mp_abort.sas
|
@li mp_abort.sas
|
||||||
|
@li mp_chop.sas
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
@@ -22219,7 +22357,10 @@ run;
|
|||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
filename &outref temp lrecl=32767;
|
%local resp_path;
|
||||||
|
%let resp_path=%sysfunc(pathname(work))/%mf_getuniquename();
|
||||||
|
filename &outref "&resp_path" lrecl=32767;
|
||||||
|
|
||||||
/* prepare request*/
|
/* prepare request*/
|
||||||
proc http method='POST' headerin=&authref in=&mainref out=&outref
|
proc http method='POST' headerin=&authref in=&mainref out=&outref
|
||||||
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
|
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
|
||||||
@@ -22227,6 +22368,7 @@ proc http method='POST' headerin=&authref in=&mainref out=&outref
|
|||||||
debug level=2;
|
debug level=2;
|
||||||
%end;
|
%end;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
|
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
|
||||||
or &mdebug=1
|
or &mdebug=1
|
||||||
%then %do;
|
%then %do;
|
||||||
@@ -22242,11 +22384,22 @@ or &mdebug=1
|
|||||||
options &optval;
|
options &optval;
|
||||||
|
|
||||||
%if &outlogds ne _null_ or &mdebug=1 %then %do;
|
%if &outlogds ne _null_ or &mdebug=1 %then %do;
|
||||||
%local dumplib;
|
%local matchstr chopout;
|
||||||
%let dumplib=%mf_getuniquelibref();
|
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
|
||||||
libname &dumplib json fileref=&outref;
|
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
|
||||||
|
|
||||||
|
%mp_chop("&resp_path"
|
||||||
|
,matchvar=matchstr
|
||||||
|
,keep=LAST
|
||||||
|
,matchpoint=END
|
||||||
|
,outfile="&chopout"
|
||||||
|
,mdebug=&mdebug
|
||||||
|
)
|
||||||
|
|
||||||
data &outlogds;
|
data &outlogds;
|
||||||
set &dumplib..log;
|
infile "&chopout" lrecl=2000;
|
||||||
|
length line $2000;
|
||||||
|
line=_infile_;
|
||||||
%if &mdebug=1 %then %do;
|
%if &mdebug=1 %then %do;
|
||||||
putlog line=;
|
putlog line=;
|
||||||
%end;
|
%end;
|
||||||
@@ -22373,50 +22526,38 @@ run;
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
/* SASjs services have the _webout embedded in wrapper JSON */
|
/* chop out JSON section */
|
||||||
/* Files can also be very large - so use a dedicated macro to chop it out */
|
%local matchstr chopout;
|
||||||
%local matchstr1 matchstr2 ;
|
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
|
||||||
%let matchstr1={"status":"success","_webout":{;
|
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
|
||||||
%let matchstr2=},"log":[{;
|
|
||||||
%let chopout1=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop1);
|
|
||||||
%let chopout2=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop2);
|
|
||||||
|
|
||||||
%mp_chop("%sysfunc(pathname(&fref1,F))"
|
%mp_chop("%sysfunc(pathname(&fref1,F))"
|
||||||
,matchvar=matchstr1
|
,matchvar=matchstr
|
||||||
,keep=LAST
|
|
||||||
,matchpoint=END
|
|
||||||
,offset=-1
|
|
||||||
,outfile="&chopout1"
|
|
||||||
,mdebug=&mdebug
|
|
||||||
)
|
|
||||||
|
|
||||||
%mp_chop("&chopout1"
|
|
||||||
,matchvar=matchstr2
|
|
||||||
,keep=FIRST
|
,keep=FIRST
|
||||||
,matchpoint=START
|
,matchpoint=START
|
||||||
,offset=1
|
,offset=-1
|
||||||
,outfile="&chopout2"
|
,outfile="&chopout"
|
||||||
,mdebug=&mdebug
|
,mdebug=&mdebug
|
||||||
)
|
)
|
||||||
|
|
||||||
%if &outlib ne 0 %then %do;
|
%if &outlib ne 0 %then %do;
|
||||||
libname &outlib json "&chopout2";
|
libname &outlib json "&chopout";
|
||||||
%end;
|
%end;
|
||||||
%if &outref ne 0 %then %do;
|
%if &outref ne 0 %then %do;
|
||||||
filename &outref "&chopout2";
|
filename &outref "&chopout";
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if &mdebug=0 %then %do;
|
%if &mdebug=0 %then %do;
|
||||||
filename &webref clear;
|
filename &webref clear;
|
||||||
filename &fref1 clear;
|
filename &fref1 clear;
|
||||||
filename &fref2 clear;
|
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
%put &sysmacroname exit vars:;
|
%put &sysmacroname exit vars:;
|
||||||
%put _local_;
|
%put _local_;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%mend ms_testservice;/**
|
%mend ms_testservice;
|
||||||
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Send data to/from sasjs/server
|
@brief Send data to/from sasjs/server
|
||||||
@details This macro should be added to the start of each web service,
|
@details This macro should be added to the start of each web service,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
%macro mf_abort(mac=mf_abort.sas, msg=, iftrue=%str(1=1)
|
%macro mf_abort(mac=mf_abort.sas, msg=, iftrue=%str(1=1)
|
||||||
)/*/STORE SOURCE*/;
|
)/des='ungraceful abort' /*STORE SOURCE*/;
|
||||||
|
|
||||||
%if not(%eval(%unquote(&iftrue))) %then %return;
|
%if not(%eval(%unquote(&iftrue))) %then %return;
|
||||||
|
|
||||||
@@ -24,4 +24,4 @@
|
|||||||
|
|
||||||
%mend mf_abort;
|
%mend mf_abort;
|
||||||
|
|
||||||
/** @endcond */
|
/** @endcond */
|
||||||
|
|||||||
@@ -25,13 +25,17 @@
|
|||||||
%local dsid rc;
|
%local dsid rc;
|
||||||
%let dsid=%sysfunc(open(&libds,is));
|
%let dsid=%sysfunc(open(&libds,is));
|
||||||
|
|
||||||
%if &dsid=0 or %length(&var)=0 %then %do;
|
%if &dsid=0 %then %do;
|
||||||
%put %sysfunc(sysmsg());
|
%put %sysfunc(sysmsg());
|
||||||
0
|
0
|
||||||
|
%end;
|
||||||
|
%else %if %length(&var)=0 %then %do;
|
||||||
|
0
|
||||||
|
%let rc=%sysfunc(close(&dsid));
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
%sysfunc(varnum(&dsid,&var))
|
%sysfunc(varnum(&dsid,&var))
|
||||||
%let rc=%sysfunc(close(&dsid));
|
%let rc=%sysfunc(close(&dsid));
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%mend mf_existvar;
|
%mend mf_existvar;
|
||||||
|
|||||||
94
base/mp_aligndecimal.sas
Normal file
94
base/mp_aligndecimal.sas
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Apply leading blanks to align numbers vertically in a char variable
|
||||||
|
@details This is particularly useful when storing numbers (as character) that
|
||||||
|
need to be sorted.
|
||||||
|
|
||||||
|
It works by splitting the number left and right of the decimal place, and
|
||||||
|
aligning it accordingly. A temporary variable is created as part of this
|
||||||
|
process (which is automatically dropped)
|
||||||
|
|
||||||
|
The macro can be used only in data step, eg as follows:
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
length myvar $50;
|
||||||
|
do i=1 to 1000 by 50;
|
||||||
|
if mod(i,2)=0 then j=ranuni(0)*i*100;
|
||||||
|
else j=i*100;
|
||||||
|
|
||||||
|
%mp_aligndecimal(myvar,width=7)
|
||||||
|
|
||||||
|
leading_spaces=length(myvar)-length(cats(myvar));
|
||||||
|
putlog +leading_spaces myvar;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
The generated code will look something like this:
|
||||||
|
|
||||||
|
length aligndp4e49996 $7;
|
||||||
|
if index(myvar,'.') then do;
|
||||||
|
aligndp4e49996=cats(scan(myvar,1,'.'));
|
||||||
|
aligndp4e49996=right(aligndp4e49996);
|
||||||
|
myvar=aligndp4e49996!!'.'!!cats(scan(myvar,2,'.'));
|
||||||
|
end;
|
||||||
|
else do;
|
||||||
|
aligndp4e49996=myvar;
|
||||||
|
aligndp4e49996=right(aligndp4e49996);
|
||||||
|
myvar=aligndp4e49996;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Results (myvar variable):
|
||||||
|
|
||||||
|
0.7683559324
|
||||||
|
122.8232796
|
||||||
|
99419.50552
|
||||||
|
42938.5143414
|
||||||
|
763.3799189
|
||||||
|
15170.606073
|
||||||
|
15083.285773
|
||||||
|
85443.198707
|
||||||
|
2022999.2251
|
||||||
|
12038.658867
|
||||||
|
1350582.6734
|
||||||
|
52777.258221
|
||||||
|
11723.347628
|
||||||
|
33101.268376
|
||||||
|
6181622.8603
|
||||||
|
7390614.0669
|
||||||
|
73384.537893
|
||||||
|
1788362.1016
|
||||||
|
2774586.2219
|
||||||
|
7998580.8415
|
||||||
|
|
||||||
|
|
||||||
|
@param var The (data step) variable to create
|
||||||
|
@param width= (8) The number of characters BEFORE the decimal point
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquename.sas
|
||||||
|
|
||||||
|
<h4> Related Programs </h4>
|
||||||
|
@li mp_aligndecimal.test.sas
|
||||||
|
|
||||||
|
@version 9.2
|
||||||
|
@author Allan Bowe
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_aligndecimal(var,width=8);
|
||||||
|
|
||||||
|
%local tmpvar;
|
||||||
|
%let tmpvar=%mf_getuniquename(prefix=aligndp);
|
||||||
|
length &tmpvar $&width;
|
||||||
|
if index(&var,'.') then do;
|
||||||
|
&tmpvar=cats(scan(&var,1,'.'));
|
||||||
|
&tmpvar=right(&tmpvar);
|
||||||
|
&var=&tmpvar!!'.'!!cats(scan(&var,2,'.'));
|
||||||
|
end;
|
||||||
|
else do;
|
||||||
|
&tmpvar=cats(&var);
|
||||||
|
&tmpvar=right(&tmpvar);
|
||||||
|
&var=&tmpvar;
|
||||||
|
end;
|
||||||
|
drop &tmpvar;
|
||||||
|
|
||||||
|
%mend mp_aligndecimal;
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
results. If it does not exist, it will be created, with the following format:
|
results. If it does not exist, it will be created, with the following format:
|
||||||
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|User Provided description|PASS|Column &inds contained ALL columns|
|
|User Provided description|PASS|Dataset &inds contained ALL columns|
|
||||||
|
|
||||||
@version 9.2
|
@version 9.2
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
results. If it does not exist, it will be created, with the following format:
|
results. If it does not exist, it will be created, with the following format:
|
||||||
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|User Provided description|PASS|Column &inds contained ALL columns|
|
|User Provided description|PASS|Dataset &inds contained ALL columns|
|
||||||
|
|
||||||
|
|
||||||
<h4> Related Macros </h4>
|
<h4> Related Macros </h4>
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
@param [in] test= (ALLVALS) The test to apply. Valid values are:
|
@param [in] test= (ALLVALS) The test to apply. Valid values are:
|
||||||
@li ALLVALS - Test is a PASS if ALL values have a match in checkvals
|
@li ALLVALS - Test is a PASS if ALL values have a match in checkvals
|
||||||
@li ANYVAL - Test is a PASS if at least 1 value has a match in checkvals
|
@li ANYVAL - Test is a PASS if at least 1 value has a match in checkvals
|
||||||
|
@li NOVAL - Test is a PASS if there are NO matches in checkvals
|
||||||
@param [out] outds= (work.test_results) The output dataset to contain the
|
@param [out] outds= (work.test_results) The output dataset to contain the
|
||||||
results. If it does not exist, it will be created, with the following format:
|
results. If it does not exist, it will be created, with the following format:
|
||||||
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
||||||
@@ -97,7 +98,7 @@
|
|||||||
|
|
||||||
%let test=%upcase(&test);
|
%let test=%upcase(&test);
|
||||||
|
|
||||||
%if &test ne ALLVALS and &test ne ANYVAL %then %do;
|
%if &test ne ALLVALS and &test ne ANYVAL and &test ne NOVAL %then %do;
|
||||||
%mp_abort(
|
%mp_abort(
|
||||||
mac=&sysmacroname,
|
mac=&sysmacroname,
|
||||||
msg=%str(Invalid test - &test)
|
msg=%str(Invalid test - &test)
|
||||||
@@ -108,12 +109,12 @@
|
|||||||
%let result=-1;
|
%let result=-1;
|
||||||
%let orig=-1;
|
%let orig=-1;
|
||||||
proc sql noprint;
|
proc sql noprint;
|
||||||
select count(*) into: result
|
select count(*) into: result trimmed
|
||||||
from &lib..&ds
|
from &lib..&ds
|
||||||
where &col not in (
|
where &col not in (
|
||||||
select &ccol from &clib..&cds
|
select &ccol from &clib..&cds
|
||||||
);
|
);
|
||||||
select count(*) into: orig from &lib..&ds;
|
select count(*) into: orig trimmed from &lib..&ds;
|
||||||
quit;
|
quit;
|
||||||
|
|
||||||
%local notfound tmp1 tmp2;
|
%local notfound tmp1 tmp2;
|
||||||
@@ -145,7 +146,7 @@
|
|||||||
length test_description $256 test_result $4 test_comments $256;
|
length test_description $256 test_result $4 test_comments $256;
|
||||||
test_description=symget('desc');
|
test_description=symget('desc');
|
||||||
test_result='FAIL';
|
test_result='FAIL';
|
||||||
test_comments="&sysmacroname: &lib..&ds..&col has &result values "
|
test_comments="&sysmacroname: &lib..&ds..&col has &result/&orig values "
|
||||||
!!"not in &clib..&cds..&ccol.. First 10 vals:"!!symget('notfound');
|
!!"not in &clib..&cds..&ccol.. First 10 vals:"!!symget('notfound');
|
||||||
%if &test=ANYVAL %then %do;
|
%if &test=ANYVAL %then %do;
|
||||||
if &result < &orig then test_result='PASS';
|
if &result < &orig then test_result='PASS';
|
||||||
@@ -153,6 +154,9 @@
|
|||||||
%else %if &test=ALLVALS %then %do;
|
%else %if &test=ALLVALS %then %do;
|
||||||
if &result=0 then test_result='PASS';
|
if &result=0 then test_result='PASS';
|
||||||
%end;
|
%end;
|
||||||
|
%else %if &test=NOVAL %then %do;
|
||||||
|
if &result=&orig then test_result='PASS';
|
||||||
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
test_comments="&sysmacroname: Unsatisfied test condition - &test";
|
test_comments="&sysmacroname: Unsatisfied test condition - &test";
|
||||||
%end;
|
%end;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
<h4> Related Macros </h4>
|
<h4> Related Macros </h4>
|
||||||
@li mf_getvarformat.sas
|
@li mf_getvarformat.sas
|
||||||
|
@li mp_aligndecimal.sas
|
||||||
@li mp_getformats.sas
|
@li mp_getformats.sas
|
||||||
@li mp_loadformat.sas
|
@li mp_loadformat.sas
|
||||||
@li mp_ds2fmtds.sas
|
@li mp_ds2fmtds.sas
|
||||||
@@ -69,13 +70,13 @@ run;
|
|||||||
data &cntlout;
|
data &cntlout;
|
||||||
if 0 then set &ddlds;
|
if 0 then set &ddlds;
|
||||||
set &cntlds;
|
set &cntlds;
|
||||||
if type="N" then do;
|
if type in ("I","N") then do; /* numeric (in)format */
|
||||||
start=cats(start);
|
%mp_aligndecimal(start,width=16)
|
||||||
end=cats(end);
|
%mp_aligndecimal(end,width=16)
|
||||||
end;
|
end;
|
||||||
run;
|
run;
|
||||||
proc sort;
|
proc sort;
|
||||||
by fmtname start;
|
by type fmtname start;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
proc sql;
|
proc sql;
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
<h4> Related Macros </h4>
|
<h4> Related Macros </h4>
|
||||||
@li mddl_dc_difftable.sas
|
@li mddl_dc_difftable.sas
|
||||||
@li mddl_dc_locktable.sas
|
@li mddl_dc_locktable.sas
|
||||||
|
@li mp_aligndecimal.sas
|
||||||
@li mp_loadformat.test.sas
|
@li mp_loadformat.test.sas
|
||||||
@li mp_lockanytable.sas
|
@li mp_lockanytable.sas
|
||||||
@li mp_stackdiffs.sas
|
@li mp_stackdiffs.sas
|
||||||
@@ -134,7 +135,16 @@ run;
|
|||||||
* First, extract only relevant formats from the catalog
|
* First, extract only relevant formats from the catalog
|
||||||
*/
|
*/
|
||||||
proc sql noprint;
|
proc sql noprint;
|
||||||
select distinct upcase(fmtname) into: fmtlist separated by ' ' from &libds;
|
select distinct
|
||||||
|
case
|
||||||
|
when type='N' then upcase(fmtname)
|
||||||
|
when type='C' then cats('$',upcase(fmtname))
|
||||||
|
when type='I' then cats('@',upcase(fmtname))
|
||||||
|
when type='J' then cats('@$',upcase(fmtname))
|
||||||
|
else "&sysmacroname:UNHANDLED"
|
||||||
|
end
|
||||||
|
into: fmtlist separated by ' '
|
||||||
|
from &libds;
|
||||||
|
|
||||||
%mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts)
|
%mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts)
|
||||||
|
|
||||||
@@ -146,16 +156,24 @@ select distinct upcase(fmtname) into: fmtlist separated by ' ' from &libds;
|
|||||||
data &inlibds;
|
data &inlibds;
|
||||||
length &delete_col $3;
|
length &delete_col $3;
|
||||||
if 0 then set &template;
|
if 0 then set &template;
|
||||||
|
length start end $10000;
|
||||||
set &libds;
|
set &libds;
|
||||||
if &delete_col='' then &delete_col='No';
|
if &delete_col='' then &delete_col='No';
|
||||||
fmtname=upcase(fmtname);
|
fmtname=upcase(fmtname);
|
||||||
|
type=upcase(type);
|
||||||
if missing(type) then do;
|
if missing(type) then do;
|
||||||
if substr(fmtname,1,1)='$' then type='C';
|
if substr(fmtname,1,1)='@' then do;
|
||||||
else type='N';
|
if substr(fmtname,2,1)='$' then type='J';
|
||||||
|
else type='I';
|
||||||
|
end;
|
||||||
|
else do;
|
||||||
|
if substr(fmtname,1,1)='$' then type='C';
|
||||||
|
else type='N';
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
if type='N' then do;
|
if type in ('N','I') then do;
|
||||||
start=cats(start);
|
%mp_aligndecimal(start,width=16)
|
||||||
end=cats(end);
|
%mp_aligndecimal(end,width=16)
|
||||||
end;
|
end;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
@@ -169,9 +187,10 @@ create table &outds_add(drop=&delete_col) as
|
|||||||
left join &base_fmts b
|
left join &base_fmts b
|
||||||
on a.fmtname=b.fmtname
|
on a.fmtname=b.fmtname
|
||||||
and a.start=b.start
|
and a.start=b.start
|
||||||
|
and a.type=b.type
|
||||||
where b.fmtname is null
|
where b.fmtname is null
|
||||||
and upcase(a.&delete_col) ne "YES"
|
and upcase(a.&delete_col) ne "YES"
|
||||||
order by fmtname, start;;
|
order by type, fmtname, start;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identify deleted records
|
* Identify deleted records
|
||||||
@@ -182,8 +201,9 @@ create table &outds_del(drop=&delete_col) as
|
|||||||
inner join &base_fmts b
|
inner join &base_fmts b
|
||||||
on a.fmtname=b.fmtname
|
on a.fmtname=b.fmtname
|
||||||
and a.start=b.start
|
and a.start=b.start
|
||||||
|
and a.type=b.type
|
||||||
where upcase(a.&delete_col)="YES"
|
where upcase(a.&delete_col)="YES"
|
||||||
order by fmtname, start;
|
order by type, fmtname, start;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identify modified records
|
* Identify modified records
|
||||||
@@ -194,8 +214,9 @@ create table &outds_mod (drop=&delete_col) as
|
|||||||
inner join &base_fmts b
|
inner join &base_fmts b
|
||||||
on a.fmtname=b.fmtname
|
on a.fmtname=b.fmtname
|
||||||
and a.start=b.start
|
and a.start=b.start
|
||||||
|
and a.type=b.type
|
||||||
where upcase(a.&delete_col) ne "YES"
|
where upcase(a.&delete_col) ne "YES"
|
||||||
order by fmtname, start;
|
order by type, fmtname, start;
|
||||||
|
|
||||||
options ibufsize=&ibufsize;
|
options ibufsize=&ibufsize;
|
||||||
|
|
||||||
@@ -212,13 +233,13 @@ options ibufsize=&ibufsize;
|
|||||||
&outds_add(in=add)
|
&outds_add(in=add)
|
||||||
&outds_del(in=del);
|
&outds_del(in=del);
|
||||||
if not del and not mod;
|
if not del and not mod;
|
||||||
by fmtname start;
|
by type fmtname start;
|
||||||
run;
|
run;
|
||||||
data &stagedata;
|
data &stagedata;
|
||||||
set &ds1 &outds_mod;
|
set &ds1 &outds_mod;
|
||||||
run;
|
run;
|
||||||
proc sort;
|
proc sort;
|
||||||
by fmtname start;
|
by type fmtname start;
|
||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
/* mp abort needs to run outside of conditional blocks */
|
/* mp abort needs to run outside of conditional blocks */
|
||||||
@@ -266,7 +287,7 @@ options ibufsize=&ibufsize;
|
|||||||
|
|
||||||
%mp_storediffs(&libcat-FC
|
%mp_storediffs(&libcat-FC
|
||||||
,&base_fmts
|
,&base_fmts
|
||||||
,FMTNAME START
|
,TYPE FMTNAME START
|
||||||
,delds=&outds_del
|
,delds=&outds_del
|
||||||
,modds=&outds_mod
|
,modds=&outds_mod
|
||||||
,appds=&outds_add
|
,appds=&outds_add
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ run;
|
|||||||
data _null_;
|
data _null_;
|
||||||
putlog 'NOTE-' / 'NOTE-';
|
putlog 'NOTE-' / 'NOTE-';
|
||||||
putlog "NOTE- &sysmacroname: table locked, waiting "@;
|
putlog "NOTE- &sysmacroname: table locked, waiting "@;
|
||||||
putlog "%sysfunc(sleep(&loop_inc)) seconds.. ";
|
putlog "%sysfunc(sleep(&loop_secs)) seconds.. ";
|
||||||
putlog "NOTE- (iteration &x of &loops)";
|
putlog "NOTE- (iteration &x of &loops)";
|
||||||
putlog 'NOTE-' / 'NOTE-';
|
putlog 'NOTE-' / 'NOTE-';
|
||||||
run;
|
run;
|
||||||
@@ -200,7 +200,10 @@ run;
|
|||||||
where LOCK_LIB ="&lib" and LOCK_DS="&ds";
|
where LOCK_LIB ="&lib" and LOCK_DS="&ds";
|
||||||
quit;
|
quit;
|
||||||
%if &syscc>0 %then %put syscc=&syscc sqlrc=&sqlrc;
|
%if &syscc>0 %then %put syscc=&syscc sqlrc=&sqlrc;
|
||||||
%if &status=LOCKED %then %do;
|
%if &sqlobs=0 %then %do;
|
||||||
|
%put %str(WAR)NING: &lib..&ds has never been locked!;
|
||||||
|
%end;
|
||||||
|
%else %if &status=LOCKED %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
putlog "&sysmacroname: unlocking &lib..&ds:";
|
putlog "&sysmacroname: unlocking &lib..&ds:";
|
||||||
run;
|
run;
|
||||||
|
|||||||
@@ -12,14 +12,20 @@
|
|||||||
|
|
||||||
proc sql;
|
proc sql;
|
||||||
create table &libds(
|
create table &libds(
|
||||||
FMTNAME char(32) label='Format name'
|
TYPE char(1) label='Type of format'
|
||||||
|
,FMTNAME char(32) label='Format name'
|
||||||
/*
|
/*
|
||||||
to accommodate larger START values, mp_loadformat.sas will need the
|
to accommodate larger START values, mp_loadformat.sas will need the
|
||||||
SQL dependency removed (proc sql needs to accommodate 3 index values in
|
SQL dependency removed (proc sql needs to accommodate 3 index values in
|
||||||
a 32767 ibufsize limit)
|
a 32767 ibufsize limit)
|
||||||
*/
|
*/
|
||||||
,START char(10000) label='Starting value for format'
|
,START char(10000) label='Starting value for format'
|
||||||
,END char(32767) label='Ending value for format'
|
/*
|
||||||
|
Keep lengths of START and END the same to avoid this err:
|
||||||
|
"Start is greater than end: -<."
|
||||||
|
Similar usage note: https://support.sas.com/kb/69/330.html
|
||||||
|
*/
|
||||||
|
,END char(10000) label='Ending value for format'
|
||||||
,LABEL char(32767) label='Format value label'
|
,LABEL char(32767) label='Format value label'
|
||||||
,MIN num length=3 label='Minimum length'
|
,MIN num length=3 label='Minimum length'
|
||||||
,MAX num length=3 label='Maximum length'
|
,MAX num length=3 label='Maximum length'
|
||||||
@@ -30,7 +36,6 @@ create table &libds(
|
|||||||
,MULT num label='Multiplier'
|
,MULT num label='Multiplier'
|
||||||
,FILL char(1) label='Fill character'
|
,FILL char(1) label='Fill character'
|
||||||
,NOEDIT num length=3 label='Is picture string noedit?'
|
,NOEDIT num length=3 label='Is picture string noedit?'
|
||||||
,TYPE char(1) label='Type of format'
|
|
||||||
,SEXCL char(1) label='Start exclusion'
|
,SEXCL char(1) label='Start exclusion'
|
||||||
,EEXCL char(1) label='End exclusion'
|
,EEXCL char(1) label='End exclusion'
|
||||||
,HLO char(13) label='Additional information'
|
,HLO char(13) label='Additional information'
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ run;
|
|||||||
filename __us2grp temp;
|
filename __us2grp temp;
|
||||||
|
|
||||||
proc metadata in= "<UpdateMetadata><Reposid>$METAREPOSITORY</Reposid><Metadata>
|
proc metadata in= "<UpdateMetadata><Reposid>$METAREPOSITORY</Reposid><Metadata>
|
||||||
<Person Id='&uuri'><IdentityGroups><IdentityGroup ObjRef='&guri' />
|
<Person Id='%nrstr(&uuri)'>
|
||||||
|
<IdentityGroups><IdentityGroup ObjRef='%nrstr(&guri)' />
|
||||||
</IdentityGroups></Person></Metadata>
|
</IdentityGroups></Person></Metadata>
|
||||||
<NS>SAS</NS><Flags>268435456</Flags></UpdateMetadata>"
|
<NS>SAS</NS><Flags>268435456</Flags></UpdateMetadata>"
|
||||||
out=__us2grp verbose;
|
out=__us2grp verbose;
|
||||||
@@ -98,4 +99,4 @@ run;
|
|||||||
|
|
||||||
filename __us2grp clear;
|
filename __us2grp clear;
|
||||||
|
|
||||||
%mend mm_adduser2group;
|
%mend mm_adduser2group;
|
||||||
|
|||||||
@@ -646,9 +646,11 @@ data _null_;
|
|||||||
put ' ';
|
put ' ';
|
||||||
put '%mend mm_webout; ';
|
put '%mend mm_webout; ';
|
||||||
/* WEBOUT END */
|
/* WEBOUT END */
|
||||||
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO);';
|
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO';
|
||||||
|
put ' ,maxobs=MAX';
|
||||||
|
put ');';
|
||||||
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
|
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
|
||||||
put ' ,showmeta=&showmeta';
|
put ' ,showmeta=&showmeta,maxobs=&maxobs';
|
||||||
put ' )';
|
put ' )';
|
||||||
put '%mend;';
|
put '%mend;';
|
||||||
run;
|
run;
|
||||||
|
|||||||
989
package-lock.json
generated
989
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,6 @@
|
|||||||
"prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true"
|
"prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sasjs/cli": "3.13.0"
|
"@sasjs/cli": "3.24.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,224 +1,224 @@
|
|||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Deploy repo as a SAS PACKAGES module
|
@brief Deploy repo as a SAS PACKAGES module
|
||||||
@details After every release, this program is executed to update the SASPAC
|
@details After every release, this program is executed to update the SASPAC
|
||||||
repo with the latest macros (and same version number).
|
repo with the latest macros (and same version number).
|
||||||
The program is first compiled using sasjs compile, then executed using
|
The program is first compiled using sasjs compile, then executed using
|
||||||
sasjs run.
|
sasjs run.
|
||||||
|
|
||||||
Requires the server to have SSH keys.
|
Requires the server to have SSH keys.
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mp_gitadd.sas
|
@li mp_gitadd.sas
|
||||||
@li mp_gitreleaseinfo.sas
|
@li mp_gitreleaseinfo.sas
|
||||||
@li mp_gitstatus.sas
|
@li mp_gitstatus.sas
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
|
||||||
/* get package version */
|
/* get package version */
|
||||||
%mp_gitreleaseinfo(GITHUB,sasjs/core,outlib=splib)
|
%mp_gitreleaseinfo(GITHUB,sasjs/core,outlib=splib)
|
||||||
data _null_;
|
data _null_;
|
||||||
set splib.root;
|
set splib.root;
|
||||||
call symputx('version',substr(TAG_NAME,2));
|
call symputx('version',substr(TAG_NAME,2));
|
||||||
run;
|
run;
|
||||||
|
|
||||||
/* clone the source repo */
|
/* clone the source repo */
|
||||||
%let dir = %sysfunc(pathname(work))/core;
|
%let dir = %sysfunc(pathname(work))/core;
|
||||||
%put source clone rc=%sysfunc(GITFN_CLONE(https://github.com/sasjs/core,&dir));
|
%put source clone rc=%sysfunc(GITFN_CLONE(https://github.com/sasjs/core,&dir));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
clone the target repo.
|
clone the target repo.
|
||||||
If you have issues, see: https://stackoverflow.com/questions/74082874
|
If you have issues, see: https://stackoverflow.com/questions/74082874
|
||||||
*/
|
*/
|
||||||
options dlcreatedir;
|
options dlcreatedir;
|
||||||
%let dirOut = %sysfunc(pathname(work))/package;
|
%let dirOut = %sysfunc(pathname(work))/package;
|
||||||
libname _ "&dirOut.";
|
libname _ "&dirOut.";
|
||||||
|
|
||||||
%put tgt clone rc=%sysfunc(GITFN_CLONE(
|
%put tgt clone rc=%sysfunc(GITFN_CLONE(
|
||||||
git@github.com:SASPAC/sasjscore.git,
|
git@github.com:SASPAC/sasjscore.git,
|
||||||
&dirOut,
|
&dirOut,
|
||||||
git,
|
git,
|
||||||
%str( ),
|
%str( ),
|
||||||
/home/sasjssrv/.ssh/id_ecdsa.pub,
|
/home/sasjssrv/.ssh/id_ecdsa.pub,
|
||||||
/home/sasjssrv/.ssh/id_ecdsa
|
/home/sasjssrv/.ssh/id_ecdsa
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Prepare Package Metadata
|
Prepare Package Metadata
|
||||||
*/
|
*/
|
||||||
data _null_;
|
data _null_;
|
||||||
infile CARDS4;
|
infile CARDS4;
|
||||||
file "&dirOut./description.sas";
|
file "&dirOut./description.sas";
|
||||||
input;
|
input;
|
||||||
if _infile_ =: 'Version:' then put "Version: &version.";
|
if _infile_ =: 'Version:' then put "Version: &version.";
|
||||||
else put _infile_;
|
else put _infile_;
|
||||||
CARDS4;
|
CARDS4;
|
||||||
Type: Package
|
Type: Package
|
||||||
Package: SASjsCore
|
Package: SASjsCore
|
||||||
Title: SAS Macros for Application Development
|
Title: SAS Macros for Application Development
|
||||||
Version: $(PLACEHOLDER)
|
Version: $(PLACEHOLDER)
|
||||||
Author: Allan Bowe
|
Author: Allan Bowe
|
||||||
Maintainer: 4GL Ltd
|
Maintainer: 4GL Ltd
|
||||||
License: MIT
|
License: MIT
|
||||||
Encoding: UTF8
|
Encoding: UTF8
|
||||||
|
|
||||||
DESCRIPTION START:
|
DESCRIPTION START:
|
||||||
|
|
||||||
The SASjs Macro Core library is a component of the SASjs framework, the
|
The SASjs Macro Core library is a component of the SASjs framework, the
|
||||||
source for which is avaible here: https://github.com/sasjs
|
source for which is avaible here: https://github.com/sasjs
|
||||||
|
|
||||||
Macros are divided by:
|
Macros are divided by:
|
||||||
|
|
||||||
* Macro Functions (prefix mf_)
|
* Macro Functions (prefix mf_)
|
||||||
* Macro Procedures (prefix mp_)
|
* Macro Procedures (prefix mp_)
|
||||||
* Macros for Metadata (prefix mm_)
|
* Macros for Metadata (prefix mm_)
|
||||||
* Macros for SASjs Server (prefix ms_)
|
* Macros for SASjs Server (prefix ms_)
|
||||||
* Macros for Viya (prefix mv_)
|
* Macros for Viya (prefix mv_)
|
||||||
|
|
||||||
DESCRIPTION END:
|
DESCRIPTION END:
|
||||||
;;;;
|
;;;;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Prepare Package License
|
Prepare Package License
|
||||||
*/
|
*/
|
||||||
data _null_;
|
data _null_;
|
||||||
file "&dirOut./license.sas";
|
file "&dirOut./license.sas";
|
||||||
infile "&dir/LICENSE";
|
infile "&dir/LICENSE";
|
||||||
input;
|
input;
|
||||||
put _infile_;
|
put _infile_;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Extract Core files into MacroCore Package location
|
Extract Core files into MacroCore Package location
|
||||||
*/
|
*/
|
||||||
data members(compress=char);
|
data members(compress=char);
|
||||||
length dref dref2 $ 8 name name2 $ 32 path $ 2048;
|
length dref dref2 $ 8 name name2 $ 32 path $ 2048;
|
||||||
rc = filename(dref, "&dir.");
|
rc = filename(dref, "&dir.");
|
||||||
put dref=;
|
put dref=;
|
||||||
did = dopen(dref);
|
did = dopen(dref);
|
||||||
if did then
|
if did then
|
||||||
do i = 1 to dnum(did);
|
do i = 1 to dnum(did);
|
||||||
name = dread(did, i);
|
name = dread(did, i);
|
||||||
if name in
|
if name in
|
||||||
("base" "ddl" "fcmp" "lua" "meta" "metax" "server" "viya" "xplatform")
|
("base" "ddl" "fcmp" "lua" "meta" "metax" "server" "viya" "xplatform")
|
||||||
then do;
|
then do;
|
||||||
rc = filename(dref2,catx("/", "&dir.", name));
|
rc = filename(dref2,catx("/", "&dir.", name));
|
||||||
put dref2= name;
|
put dref2= name;
|
||||||
did2 = dopen(dref2);
|
did2 = dopen(dref2);
|
||||||
|
|
||||||
if did2 then
|
if did2 then
|
||||||
do j = 1 to dnum(did2);
|
do j = 1 to dnum(did2);
|
||||||
name2 = dread(did2, j);
|
name2 = dread(did2, j);
|
||||||
path = catx("/", "&dir.", name, name2);
|
path = catx("/", "&dir.", name, name2);
|
||||||
if "sas" = scan(name2, -1, ".") then output;
|
if "sas" = scan(name2, -1, ".") then output;
|
||||||
end;
|
end;
|
||||||
rc = dclose(did2);
|
rc = dclose(did2);
|
||||||
rc = filename(dref2);
|
rc = filename(dref2);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
rc = dclose(did);
|
rc = dclose(did);
|
||||||
rc = filename(dref);
|
rc = filename(dref);
|
||||||
keep name name2 path;
|
keep name name2 path;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%let temp_options = %sysfunc(getoption(source)) %sysfunc(getoption(notes));
|
%let temp_options = %sysfunc(getoption(source)) %sysfunc(getoption(notes));
|
||||||
options nosource nonotes;
|
options nosource nonotes;
|
||||||
data _null_;
|
data _null_;
|
||||||
set members;
|
set members;
|
||||||
by name notsorted;
|
by name notsorted;
|
||||||
|
|
||||||
ord + first.name;
|
ord + first.name;
|
||||||
|
|
||||||
if first.name then
|
if first.name then
|
||||||
do;
|
do;
|
||||||
call execute('libname _ '
|
call execute('libname _ '
|
||||||
!! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros"))
|
!! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros"))
|
||||||
!! ";"
|
!! ";"
|
||||||
);
|
);
|
||||||
put @1 "./" ord z3. "_macros/";
|
put @1 "./" ord z3. "_macros/";
|
||||||
end;
|
end;
|
||||||
|
|
||||||
put @10 name2;
|
put @10 name2;
|
||||||
call execute("
|
call execute("
|
||||||
data _null_;
|
data _null_;
|
||||||
infile " !! quote(strip(path)) !! ";
|
infile " !! quote(strip(path)) !! ";
|
||||||
file " !! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros", name2)) !!";
|
file " !! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros", name2)) !!";
|
||||||
input;
|
input;
|
||||||
select;
|
select;
|
||||||
when (2 = trigger) put _infile_;
|
when (2 = trigger) put _infile_;
|
||||||
when (_infile_ = '/**') do; put '/*** HELP START ***//**'; trigger+1; end;
|
when (_infile_ = '/**') do; put '/*** HELP START ***//**'; trigger+1; end;
|
||||||
when (_infile_ = '**/') do; put '**//*** HELP END ***/'; trigger+1; end;
|
when (_infile_ = '**/') do; put '**//*** HELP END ***/'; trigger+1; end;
|
||||||
otherwise put _infile_;
|
otherwise put _infile_;
|
||||||
end;
|
end;
|
||||||
run;");
|
run;");
|
||||||
|
|
||||||
run;
|
run;
|
||||||
options &temp_options.;
|
options &temp_options.;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Generate SASjsCore Package
|
Generate SASjsCore Package
|
||||||
*/
|
*/
|
||||||
%GeneratePackage(
|
%GeneratePackage(
|
||||||
filesLocation=&dirOut
|
filesLocation=&dirOut
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* apply new version in a github action
|
* apply new version in a github action
|
||||||
* 1. create folder
|
* 1. create folder
|
||||||
* 2. create template yaml
|
* 2. create template yaml
|
||||||
* 3. replace version number
|
* 3. replace version number
|
||||||
*/
|
*/
|
||||||
|
|
||||||
%mf_mkdir(&dirout/.github/workflows)
|
%mf_mkdir(&dirout/.github/workflows)
|
||||||
|
|
||||||
%let desc=Version &version of sasjs/core is now on SAS PACKAGES :ok_hand:;
|
%let desc=Version &version of sasjs/core is now on SAS PACKAGES :ok_hand:;
|
||||||
data _null_;
|
data _null_;
|
||||||
file "&dirout/.github/workflows/release.yml";
|
file "&dirout/.github/workflows/release.yml";
|
||||||
put "name: SASjs Core Package Publish Tag";
|
put "name: SASjs Core Package Publish Tag";
|
||||||
put "on:";
|
put "on:";
|
||||||
put " push:";
|
put " push:";
|
||||||
put " branches:";
|
put " branches:";
|
||||||
put " - main";
|
put " - main";
|
||||||
put "jobs:";
|
put "jobs:";
|
||||||
put " update:";
|
put " update:";
|
||||||
put " runs-on: ubuntu-latest";
|
put " runs-on: ubuntu-latest";
|
||||||
put " steps:";
|
put " steps:";
|
||||||
put " - uses: actions/checkout@master";
|
put " - uses: actions/checkout@master";
|
||||||
put " - name: Make Release";
|
put " - name: Make Release";
|
||||||
put " uses: alice-biometrics/release-creator/@v1.0.5";
|
put " uses: alice-biometrics/release-creator/@v1.0.5";
|
||||||
put " with:";
|
put " with:";
|
||||||
put " github_token: ${{ secrets.GH_TOKEN }}";
|
put " github_token: ${{ secrets.GH_TOKEN }}";
|
||||||
put " branch: main";
|
put " branch: main";
|
||||||
put " draft: false";
|
put " draft: false";
|
||||||
put " version: &version";
|
put " version: &version";
|
||||||
put " description: '&desc'";
|
put " description: '&desc'";
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add, Commit & Push!
|
* Add, Commit & Push!
|
||||||
*/
|
*/
|
||||||
%mp_gitstatus(&dirout,outds=work.gitstatus,mdebug=1)
|
%mp_gitstatus(&dirout,outds=work.gitstatus,mdebug=1)
|
||||||
%mp_gitadd(&dirout,inds=work.gitstatus,mdebug=1)
|
%mp_gitadd(&dirout,inds=work.gitstatus,mdebug=1)
|
||||||
|
|
||||||
data _null_;
|
data _null_;
|
||||||
rc=gitfn_commit("&dirout"
|
rc=gitfn_commit("&dirout"
|
||||||
,"HEAD","&sysuserid","sasjs@core"
|
,"HEAD","&sysuserid","sasjs@core"
|
||||||
,"FEAT: Releasing &version"
|
,"FEAT: Releasing &version"
|
||||||
);
|
);
|
||||||
put rc=;
|
put rc=;
|
||||||
rc=git_push(
|
rc=git_push(
|
||||||
"&dirout"
|
"&dirout"
|
||||||
,"git"
|
,"git"
|
||||||
,""
|
,""
|
||||||
,"/home/sasjssrv/.ssh/id_ecdsa.pub"
|
,"/home/sasjssrv/.ssh/id_ecdsa.pub"
|
||||||
,"/home/sasjssrv/.ssh/id_ecdsa"
|
,"/home/sasjssrv/.ssh/id_ecdsa"
|
||||||
);
|
);
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,9 @@
|
|||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_getuniquefileref.sas
|
@li mf_getuniquefileref.sas
|
||||||
@li mf_getuniquelibref.sas
|
@li mf_getuniquename.sas
|
||||||
@li mp_abort.sas
|
@li mp_abort.sas
|
||||||
|
@li mp_chop.sas
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
@@ -153,7 +154,10 @@ run;
|
|||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
filename &outref temp lrecl=32767;
|
%local resp_path;
|
||||||
|
%let resp_path=%sysfunc(pathname(work))/%mf_getuniquename();
|
||||||
|
filename &outref "&resp_path" lrecl=32767;
|
||||||
|
|
||||||
/* prepare request*/
|
/* prepare request*/
|
||||||
proc http method='POST' headerin=&authref in=&mainref out=&outref
|
proc http method='POST' headerin=&authref in=&mainref out=&outref
|
||||||
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
|
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
|
||||||
@@ -161,6 +165,7 @@ proc http method='POST' headerin=&authref in=&mainref out=&outref
|
|||||||
debug level=2;
|
debug level=2;
|
||||||
%end;
|
%end;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
|
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
|
||||||
or &mdebug=1
|
or &mdebug=1
|
||||||
%then %do;
|
%then %do;
|
||||||
@@ -176,11 +181,22 @@ or &mdebug=1
|
|||||||
options &optval;
|
options &optval;
|
||||||
|
|
||||||
%if &outlogds ne _null_ or &mdebug=1 %then %do;
|
%if &outlogds ne _null_ or &mdebug=1 %then %do;
|
||||||
%local dumplib;
|
%local matchstr chopout;
|
||||||
%let dumplib=%mf_getuniquelibref();
|
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
|
||||||
libname &dumplib json fileref=&outref;
|
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
|
||||||
|
|
||||||
|
%mp_chop("&resp_path"
|
||||||
|
,matchvar=matchstr
|
||||||
|
,keep=LAST
|
||||||
|
,matchpoint=END
|
||||||
|
,outfile="&chopout"
|
||||||
|
,mdebug=&mdebug
|
||||||
|
)
|
||||||
|
|
||||||
data &outlogds;
|
data &outlogds;
|
||||||
set &dumplib..log;
|
infile "&chopout" lrecl=2000;
|
||||||
|
length line $2000;
|
||||||
|
line=_infile_;
|
||||||
%if &mdebug=1 %then %do;
|
%if &mdebug=1 %then %do;
|
||||||
putlog line=;
|
putlog line=;
|
||||||
%end;
|
%end;
|
||||||
|
|||||||
@@ -108,47 +108,34 @@ run;
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
/* SASjs services have the _webout embedded in wrapper JSON */
|
/* chop out JSON section */
|
||||||
/* Files can also be very large - so use a dedicated macro to chop it out */
|
%local matchstr chopout;
|
||||||
%local matchstr1 matchstr2 ;
|
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
|
||||||
%let matchstr1={"status":"success","_webout":{;
|
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
|
||||||
%let matchstr2=},"log":[{;
|
|
||||||
%let chopout1=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop1);
|
|
||||||
%let chopout2=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop2);
|
|
||||||
|
|
||||||
%mp_chop("%sysfunc(pathname(&fref1,F))"
|
%mp_chop("%sysfunc(pathname(&fref1,F))"
|
||||||
,matchvar=matchstr1
|
,matchvar=matchstr
|
||||||
,keep=LAST
|
|
||||||
,matchpoint=END
|
|
||||||
,offset=-1
|
|
||||||
,outfile="&chopout1"
|
|
||||||
,mdebug=&mdebug
|
|
||||||
)
|
|
||||||
|
|
||||||
%mp_chop("&chopout1"
|
|
||||||
,matchvar=matchstr2
|
|
||||||
,keep=FIRST
|
,keep=FIRST
|
||||||
,matchpoint=START
|
,matchpoint=START
|
||||||
,offset=1
|
,offset=-1
|
||||||
,outfile="&chopout2"
|
,outfile="&chopout"
|
||||||
,mdebug=&mdebug
|
,mdebug=&mdebug
|
||||||
)
|
)
|
||||||
|
|
||||||
%if &outlib ne 0 %then %do;
|
%if &outlib ne 0 %then %do;
|
||||||
libname &outlib json "&chopout2";
|
libname &outlib json "&chopout";
|
||||||
%end;
|
%end;
|
||||||
%if &outref ne 0 %then %do;
|
%if &outref ne 0 %then %do;
|
||||||
filename &outref "&chopout2";
|
filename &outref "&chopout";
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if &mdebug=0 %then %do;
|
%if &mdebug=0 %then %do;
|
||||||
filename &webref clear;
|
filename &webref clear;
|
||||||
filename &fref1 clear;
|
filename &fref1 clear;
|
||||||
filename &fref2 clear;
|
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
%put &sysmacroname exit vars:;
|
%put &sysmacroname exit vars:;
|
||||||
%put _local_;
|
%put _local_;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%mend ms_testservice;
|
%mend ms_testservice;
|
||||||
|
|||||||
@@ -17,4 +17,24 @@
|
|||||||
%mp_assert(
|
%mp_assert(
|
||||||
iftrue=(%mf_existvar(sashelp.class,isjustanumber)=0),
|
iftrue=(%mf_existvar(sashelp.class,isjustanumber)=0),
|
||||||
desc=Checking non existing var does not exist
|
desc=Checking non existing var does not exist
|
||||||
|
)
|
||||||
|
|
||||||
|
data work.lockcheck;
|
||||||
|
a=1;
|
||||||
|
output;
|
||||||
|
stop;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(%mf_existvar(work.lockcheck,)=0),
|
||||||
|
desc=Checking non-provided var does not exist
|
||||||
|
)
|
||||||
|
|
||||||
|
proc sql;
|
||||||
|
update work.lockcheck set a=2;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc=0),
|
||||||
|
desc=Checking the lock was released,
|
||||||
|
outds=work.test_results
|
||||||
)
|
)
|
||||||
46
tests/base/mp_aligndecimal.test.sas
Normal file
46
tests/base/mp_aligndecimal.test.sas
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_aligndecimal macro
|
||||||
|
@details Creates an aligned variable and checks the number of leading blanks
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_aligndecimal.sas
|
||||||
|
@li mp_assertcolvals.sas
|
||||||
|
@li mp_assertscope.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* target values */
|
||||||
|
data work.checkds;
|
||||||
|
do checkval=' 0.56',' 123.45',' 123.4 ',' 1.2 ',' 0';
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
/* raw values */
|
||||||
|
data work.rawds;
|
||||||
|
set work.checkds;
|
||||||
|
tgtvar=cats(checkval);
|
||||||
|
drop checkval;
|
||||||
|
run;
|
||||||
|
%mp_assertcolvals(work.rawds.tgtvar,
|
||||||
|
checkvals=work.checkds.checkval,
|
||||||
|
desc=No values match (ready to align),
|
||||||
|
test=NOVAL
|
||||||
|
)
|
||||||
|
|
||||||
|
/* aligned values */
|
||||||
|
%mp_assertscope(SNAPSHOT)
|
||||||
|
data work.finalds;
|
||||||
|
set work.rawds;
|
||||||
|
%mp_aligndecimal(tgtvar,width=4)
|
||||||
|
run;
|
||||||
|
%mp_assertscope(COMPARE)
|
||||||
|
|
||||||
|
%mp_assertcolvals(work.finalds.tgtvar,
|
||||||
|
checkvals=work.checkds.checkval,
|
||||||
|
desc=All values match (aligned),
|
||||||
|
test=ALLVALS
|
||||||
|
)
|
||||||
@@ -7,23 +7,35 @@
|
|||||||
@li mp_assertcols.sas
|
@li mp_assertcols.sas
|
||||||
@li mp_assertcolvals.sas
|
@li mp_assertcolvals.sas
|
||||||
@li mp_assertdsobs.sas
|
@li mp_assertdsobs.sas
|
||||||
|
@li mp_assertscope.sas
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
|
||||||
/* valid filter */
|
/* make some data */
|
||||||
%mp_getcols(sashelp.airline,outds=work.info)
|
proc sql;
|
||||||
|
create table work.src(
|
||||||
|
SOME_DATETIME float format=datetime19.,
|
||||||
|
SOME_CHAR char(16),
|
||||||
|
SOME_NUM num,
|
||||||
|
SOME_TIME num format=time8.,
|
||||||
|
SOME_DATE num format=date9.
|
||||||
|
);
|
||||||
|
|
||||||
|
/* run macro, checking for scope leakage */
|
||||||
|
%mp_assertscope(SNAPSHOT)
|
||||||
|
%mp_getcols(work.src,outds=work.info)
|
||||||
|
%mp_assertscope(COMPARE)
|
||||||
|
|
||||||
%mp_assertdsobs(work.info,
|
%mp_assertdsobs(work.info,
|
||||||
desc=Has 3 records,
|
desc=Has 5 records,
|
||||||
test=EQUALS 3,
|
test=EQUALS 5,
|
||||||
outds=work.test_results
|
outds=work.test_results
|
||||||
)
|
)
|
||||||
|
|
||||||
data work.check;
|
data work.check;
|
||||||
length val $10;
|
length val $10;
|
||||||
do val='NUMERIC','DATE','CHARACTER';
|
do val='NUMERIC','DATE','CHARACTER','DATETIME','TIME';
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
run;
|
run;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Testing mp_loadformat.sas macro
|
@brief Testing mp_loadformat.sas macro
|
||||||
|
@details first test regular formats, then informats
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mddl_dc_difftable.sas
|
@li mddl_dc_difftable.sas
|
||||||
|
@li mp_aligndecimal.sas
|
||||||
@li mp_loadformat.sas
|
@li mp_loadformat.sas
|
||||||
@li mp_assert.sas
|
@li mp_assert.sas
|
||||||
@li mp_assertscope.sas
|
@li mp_assertscope.sas
|
||||||
@@ -15,8 +17,10 @@ libname perm (work);
|
|||||||
|
|
||||||
%mddl_dc_difftable(libds=perm.audit)
|
%mddl_dc_difftable(libds=perm.audit)
|
||||||
|
|
||||||
|
/* set up regular formats */
|
||||||
data work.loadfmts;
|
data work.loadfmts;
|
||||||
length fmtname $32;
|
/* matching start / end lengths (to baseds) are important */
|
||||||
|
length fmtname $32 start end $10000;
|
||||||
eexcl='Y';
|
eexcl='Y';
|
||||||
type='N';
|
type='N';
|
||||||
do i=1 to 100;
|
do i=1 to 100;
|
||||||
@@ -24,7 +28,9 @@ data work.loadfmts;
|
|||||||
do j=1 to 100;
|
do j=1 to 100;
|
||||||
start=cats(j);
|
start=cats(j);
|
||||||
end=cats(j+1);
|
end=cats(j+1);
|
||||||
label= cats('Dummy ',start);
|
%mp_aligndecimal(start,width=16)
|
||||||
|
%mp_aligndecimal(end,width=16)
|
||||||
|
label= cats('Numeric Format ',start);
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -42,6 +48,8 @@ data work.stagedata;
|
|||||||
else if _n_<350 then do;
|
else if _n_<350 then do;
|
||||||
start=cats(_n_);
|
start=cats(_n_);
|
||||||
end=cats(_n_+1);
|
end=cats(_n_+1);
|
||||||
|
%mp_aligndecimal(start,width=16)
|
||||||
|
%mp_aligndecimal(end,width=16)
|
||||||
label='newval'!!cats(_N_);
|
label='newval'!!cats(_N_);
|
||||||
end;
|
end;
|
||||||
else stop;
|
else stop;
|
||||||
@@ -91,3 +99,118 @@ run;
|
|||||||
desc=Test 1 - diffs were found,
|
desc=Test 1 - diffs were found,
|
||||||
outds=work.test_results
|
outds=work.test_results
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/* set up a mix of formats */
|
||||||
|
data work.loadfmts2;
|
||||||
|
length fmtname $32 start end $10000;
|
||||||
|
eexcl='Y';
|
||||||
|
type='J';
|
||||||
|
do i=1 to 3;
|
||||||
|
fmtname=cats('SASJS_CI_',i,'X');
|
||||||
|
do j=1 to 4;
|
||||||
|
start=cats(j);
|
||||||
|
end=start;
|
||||||
|
label= cats('Char INFORMAT ',start);
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
type='I';
|
||||||
|
do i=1 to 3;
|
||||||
|
fmtname=cats('SASJS_NI_',i,'X');
|
||||||
|
do j=1 to 4;
|
||||||
|
start=cats(j);
|
||||||
|
end=cats(j+1);
|
||||||
|
%mp_aligndecimal(start,width=16)
|
||||||
|
%mp_aligndecimal(end,width=16)
|
||||||
|
label= cats(ranuni(0));
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
type='N';
|
||||||
|
do i=1 to 3;
|
||||||
|
fmtname=cats('SASJS_NF_',i,'X');
|
||||||
|
do j=1 to 4;
|
||||||
|
start=cats(j);
|
||||||
|
end=cats(j+1);
|
||||||
|
%mp_aligndecimal(start,width=16)
|
||||||
|
%mp_aligndecimal(end,width=16)
|
||||||
|
label= cats('Numeric Format ',start);
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
type='C';
|
||||||
|
do i=1 to 3;
|
||||||
|
fmtname=cats('SASJS_CF_',i,'X');
|
||||||
|
do j=1 to 4;
|
||||||
|
start=cats(j);
|
||||||
|
end=start;
|
||||||
|
label= cats('Char Format ',start);
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
drop i j;
|
||||||
|
run;
|
||||||
|
proc format cntlin=work.loadfmts2 library=perm.testcat2;
|
||||||
|
run;
|
||||||
|
|
||||||
|
/* make some test data */
|
||||||
|
data work.stagedata2;
|
||||||
|
set work.loadfmts2;
|
||||||
|
where type in ('I','J');
|
||||||
|
eexcl='Y';
|
||||||
|
if type='I' then do;
|
||||||
|
i+1;
|
||||||
|
if i<3 then deleteme='Yes';
|
||||||
|
else if i<7 then label= cats(ranuni(0)*100);
|
||||||
|
else if i<12 then do;
|
||||||
|
/* new values */
|
||||||
|
z=ranuni(0)*1000000;
|
||||||
|
start=cats(z);
|
||||||
|
end=cats(z+1);
|
||||||
|
%mp_aligndecimal(start,width=16)
|
||||||
|
%mp_aligndecimal(end,width=16)
|
||||||
|
label= cats(ranuni(0)*100);
|
||||||
|
end;
|
||||||
|
if i<12 then output;
|
||||||
|
end;
|
||||||
|
else do;
|
||||||
|
j+1;
|
||||||
|
if j<3 then deleteme='Yes';
|
||||||
|
else if j<7 then label= cats(ranuni(0)*100);
|
||||||
|
else if j<12 then do;
|
||||||
|
start= cats("NEWVAL",start);
|
||||||
|
end=start;
|
||||||
|
label= "NEWVAL "||cats(ranuni(0)*100);
|
||||||
|
end;
|
||||||
|
if j<12 then output;
|
||||||
|
end;
|
||||||
|
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_loadformat(perm.testcat2
|
||||||
|
,work.stagedata2
|
||||||
|
,loadtarget=YES
|
||||||
|
,auditlibds=perm.audit
|
||||||
|
,locklibds=0
|
||||||
|
,delete_col=deleteme
|
||||||
|
,outds_add=add_test2
|
||||||
|
,outds_del=del_test2
|
||||||
|
,outds_mod=mod_test2
|
||||||
|
,mdebug=1
|
||||||
|
)
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(%mf_nobs(del_test2)=4),
|
||||||
|
desc=Test 2 - delete obs,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(%mf_nobs(mod_test2)=8),
|
||||||
|
desc=Test 2 - mod obs,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(%mf_nobs(add_test2)=10),
|
||||||
|
desc=Test 2 - add obs,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mp_lockanytable.sas
|
@li mp_lockanytable.sas
|
||||||
|
@li mp_assert.sas
|
||||||
@li mp_assertcols.sas
|
@li mp_assertcols.sas
|
||||||
@li mp_assertcolvals.sas
|
@li mp_assertcolvals.sas
|
||||||
|
@li mp_assertscope.sas
|
||||||
@li mp_coretable.sas
|
@li mp_coretable.sas
|
||||||
|
|
||||||
**/
|
**/
|
||||||
@@ -61,3 +63,18 @@ run;
|
|||||||
desc=Ref is captured in unlock,
|
desc=Ref is captured in unlock,
|
||||||
test=ANYVAL
|
test=ANYVAL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/* attempt unlock of a table that was never locked */
|
||||||
|
|
||||||
|
%mp_lockanytable(UNLOCK,lib=no,ds=doesnotexist,ref=bye, ctl_ds=work.controller)
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc=0),
|
||||||
|
desc=Ability to unlock a table that was never locked,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* test for macro variable scope leakage */
|
||||||
|
%mp_assertscope(SNAPSHOT)
|
||||||
|
%mp_lockanytable(LOCK,lib=tmp,ds=testscope,ref=This Ref, ctl_ds=work.controller)
|
||||||
|
%mp_assertscope(COMPARE)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
@brief Testing mv_jobflow macro
|
@brief Testing mv_jobflow macro
|
||||||
@details One of the remote jobs aborts with syscc>0 - test to
|
@details One of the remote jobs aborts with syscc>0 - test to
|
||||||
make sure this comes back to the calling session
|
make sure this comes back to the calling session
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mp_assert.sas
|
@li mp_assert.sas
|
||||||
@li mv_createjob.sas
|
@li mv_createjob.sas
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@brief Testing mv_jobflow macro
|
@brief Testing mv_jobflow macro
|
||||||
@details All jobs complete successfully with syscc = 0 - test to
|
@details All jobs complete successfully with syscc = 0 - test to
|
||||||
make sure this comes back to the calling session
|
make sure this comes back to the calling session
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mp_assert.sas
|
@li mp_assert.sas
|
||||||
@li mv_createjob.sas
|
@li mv_createjob.sas
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
@brief Testing mv_registerclient.sas macro
|
@brief Testing mv_registerclient.sas macro
|
||||||
@details Tests for successful registration. For this to work, the test
|
@details Tests for successful registration. For this to work, the test
|
||||||
account must be an admin.
|
account must be an admin.
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_getuniquename.sas
|
@li mf_getuniquename.sas
|
||||||
@li mp_assertcolvals.sas
|
@li mp_assertcolvals.sas
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
|
|
||||||
@file
|
@file
|
||||||
@brief Testing mv_registerclient.sas macro
|
@brief Testing mv_registerclient.sas macro
|
||||||
@details Tests for unsuccessful registration. To do this, overrides are
|
@details Tests for unsuccessful registration. To do this, overrides are
|
||||||
applied for the mf_loc.sas and mp_abort.sas macros.
|
applied for the mf_loc.sas and mp_abort.sas macros.
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mp_assert.sas
|
@li mp_assert.sas
|
||||||
@li mv_registerclient.sas
|
@li mv_registerclient.sas
|
||||||
|
|||||||
@@ -1,60 +1,60 @@
|
|||||||
/**
|
/**
|
||||||
@file mfv_existsashdat.sas
|
@file mfv_existsashdat.sas
|
||||||
@brief Checks whether a CAS sashdat dataset exists in persistent storage.
|
@brief Checks whether a CAS sashdat dataset exists in persistent storage.
|
||||||
@details Can be used in open code, eg as follows:
|
@details Can be used in open code, eg as follows:
|
||||||
|
|
||||||
%if %mfv_existsashdat(libds=casuser.sometable) %then %put yes it does!;
|
%if %mfv_existsashdat(libds=casuser.sometable) %then %put yes it does!;
|
||||||
|
|
||||||
The function uses `dosubl()` to run the `table.fileinfo` action, for the
|
The function uses `dosubl()` to run the `table.fileinfo` action, for the
|
||||||
specified library, filtering for `*.sashdat` tables. The results are stored
|
specified library, filtering for `*.sashdat` tables. The results are stored
|
||||||
in a WORK table (&outprefix._&lib). If that table already exists, it is
|
in a WORK table (&outprefix._&lib). If that table already exists, it is
|
||||||
queried instead, to avoid the dosubl() performance hit.
|
queried instead, to avoid the dosubl() performance hit.
|
||||||
|
|
||||||
To force a rescan, just use a new `&outprefix` value, or delete the table(s)
|
To force a rescan, just use a new `&outprefix` value, or delete the table(s)
|
||||||
before running the function.
|
before running the function.
|
||||||
|
|
||||||
@param libds library.dataset
|
@param libds library.dataset
|
||||||
@param outprefix= (work.mfv_existsashdat) Used to store the current HDATA
|
@param outprefix= (work.mfv_existsashdat) Used to store the current HDATA
|
||||||
tables to improve subsequent query performance. This reference is a prefix
|
tables to improve subsequent query performance. This reference is a prefix
|
||||||
and is converted to `&prefix._{libref}`
|
and is converted to `&prefix._{libref}`
|
||||||
|
|
||||||
@return output returns 1 or 0
|
@return output returns 1 or 0
|
||||||
|
|
||||||
@version 0.2
|
@version 0.2
|
||||||
@author Mathieu Blauw
|
@author Mathieu Blauw
|
||||||
**/
|
**/
|
||||||
|
|
||||||
%macro mfv_existsashdat(libds,outprefix=work.mfv_existsashdat
|
%macro mfv_existsashdat(libds,outprefix=work.mfv_existsashdat
|
||||||
);
|
);
|
||||||
%local rc dsid name lib ds;
|
%local rc dsid name lib ds;
|
||||||
%let lib=%upcase(%scan(&libds,1,'.'));
|
%let lib=%upcase(%scan(&libds,1,'.'));
|
||||||
%let ds=%upcase(%scan(&libds,-1,'.'));
|
%let ds=%upcase(%scan(&libds,-1,'.'));
|
||||||
|
|
||||||
/* if table does not exist, create it */
|
/* if table does not exist, create it */
|
||||||
%if %sysfunc(exist(&outprefix._&lib)) ne 1 %then %do;
|
%if %sysfunc(exist(&outprefix._&lib)) ne 1 %then %do;
|
||||||
%let rc=%sysfunc(dosubl(%nrstr(
|
%let rc=%sysfunc(dosubl(%nrstr(
|
||||||
/* Read in table list (once per &lib per session) */
|
/* Read in table list (once per &lib per session) */
|
||||||
proc cas;
|
proc cas;
|
||||||
table.fileinfo result=source_list /caslib="&lib";
|
table.fileinfo result=source_list /caslib="&lib";
|
||||||
val=findtable(source_list);
|
val=findtable(source_list);
|
||||||
saveresult val dataout=&outprefix._&lib;
|
saveresult val dataout=&outprefix._&lib;
|
||||||
quit;
|
quit;
|
||||||
/* Only keep name, without file extension */
|
/* Only keep name, without file extension */
|
||||||
data &outprefix._&lib;
|
data &outprefix._&lib;
|
||||||
set &outprefix._&lib(where=(Name like '%.sashdat') keep=Name);
|
set &outprefix._&lib(where=(Name like '%.sashdat') keep=Name);
|
||||||
Name=upcase(scan(Name,1,'.'));
|
Name=upcase(scan(Name,1,'.'));
|
||||||
run;
|
run;
|
||||||
)));
|
)));
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
/* Scan table for hdat existence */
|
/* Scan table for hdat existence */
|
||||||
%let dsid=%sysfunc(open(&outprefix._&lib(where=(name="&ds"))));
|
%let dsid=%sysfunc(open(&outprefix._&lib(where=(name="&ds"))));
|
||||||
%syscall set(dsid);
|
%syscall set(dsid);
|
||||||
%let rc = %sysfunc(fetch(&dsid));
|
%let rc = %sysfunc(fetch(&dsid));
|
||||||
%let rc = %sysfunc(close(&dsid));
|
%let rc = %sysfunc(close(&dsid));
|
||||||
|
|
||||||
/* Return result */
|
/* Return result */
|
||||||
%if "%trim(&name)"="%trim(&ds)" %then 1;
|
%if "%trim(&name)"="%trim(&ds)" %then 1;
|
||||||
%else 0;
|
%else 0;
|
||||||
|
|
||||||
%mend mfv_existsashdat;
|
%mend mfv_existsashdat;
|
||||||
|
|||||||
Reference in New Issue
Block a user